1 #define VERSION "5.2 - July 1, 2021"
2 #define SWITCHES "[-uagsETh -Ac#txm#P#bpe#f#q -odGVX -v]"
3 #define TMP
4 
5 /* plantri.c :  generate imbedded planar graphs
6 
7   This program generates many different classes of graph imbedded on
8   a sphere.  Exact specifications and instructions for use can be found
9   in the separate manual plantri-guide.txt.
10 
11   The latest edition of plantri is available from the plantri page
12   https://users.cecs.anu.edu.au/~bdm/plantri
13 
14   Authors:  Gunnar Brinkmann   Gunnar.Brinkmann@ugent.be
15             Brendan McKay      Brendan.McKay@anu.edu.au
16 
17 ---------
18 
19    Output formats:
20 
21       The output for each graph consists of the number of vertices,
22       then for each vertex a list of all its neighbours in clockwise
23       order.  These neighbour lists are separated by a "separator",
24       and terminated by a "terminator".
25 
26                              planar_code          ascii format
27                               (default)            (with -a)
28 
29       file type               binary               text
30       number of vertices      one byte          decimal + blank
31       vertex names          bytes 1,2,3...        letters 'a','b',...
32       separators              zero byte           comma ','
33       terminator              zero byte           newline '\n'
34 
35       For example, the planar dual of the cube appears like this:
36 
37       planar_code:
38          6 4 3 2 5 0 3 6 5 1 0 1 4 6 2 0 5 6 3 1 0 4 1 2 6 0 4 5 2 3 0
39          (One number per byte, no newlines).
40 
41       ascii format:
42          6 dcbe,cfea,adfb,efca,dabf,debc
43          (Including the space after "6".)  Followed by newline.
44          This is the same as planar_code but human-readable.
45 
46       edge_code:
47 	 See the manual.  At the moment there is a limit of 255 on the
48          number of undirected edges.  This could be increased.
49 
50       double_code:
51          The primal and dual graphs are written in a human-readable form
52          of edge_code. The -d switch determines which is written first.
53          There is a limit of 155 edges.
54 
55       For planar_code, the standard header ">>planar_code<<"
56       (without null or newline) is written at the start of the
57       output unless the -h switch is given.  Similarly for edge_code
58       and the header ">>edge_code<<".
59 
60       For graphs with multiple loops, edge_code and text edgecode are
61       the only output formats which are completely unambiguous.
62 
63       Using -g or -s, the graph6 or sparse6 formats can be selected instead.
64       These are ASCII formats for general undirected graphs, and do not
65       encode the imbedding.  graph6 does not represent loops or edge
66       multiplicities either.  They are described in plantri-guide.txt.
67 
68 ---------
69 
70 Size limits:
71 
72 The space used by plantri is O(n^2).  Apart from that, the only
73 practical limits on MAXN (the maximum permitted number of vertices)
74 is determined by the limits imposed by the output syntax.
75 
76 The following table gives the largest legal MAXN value.
77 
78  Switches:    none    -d    -a    -ad    -g    -gd   -s    -sd      -u
79  Output:      planar_code     ascii        graph6     sparse6      none
80              primal  dual  primal dual  primal dual  primal dual
81  MAXN limit:  255    129     99     51   255   129    255   129    1023
82 
83  Switches -E and -Ed give edge_code output.  These have no limit on the
84  number of vertices but (currently) a limit of 255 on the number of
85  undirected edges.
86 
87  Switches -T and -Td give double_code output. See above and the guide.
88 
89 The limits for ascii code could be raised to 114 and 59 easily.
90 For connectivity < 3, there is also a limit on n of the number of
91 bits in a long int (usually 32 or 64).
92 
93 Change History:
94 
95         5-Jun-1996 : initial release of version 1.0
96         7-Jun-1996 : fixed writing of planar_code header
97                      small changes to plug-in facility
98                      -- making 1.0.1
99         9-Jun-1996 : included PLUGIN_INIT facility
100                      -- making 1.0.2
101        13-Jul-1996 : added -g switch
102                      -- making 1.0.3
103        31-Jul-1997 : added BIGTODOUBLE macro
104                      -- making 1.0.4
105         5-Aug-1997 : relaxed and documented MAXN limit
106                      -- making 1.0.5
107        20-Sep-1998 : improved performance about 25%
108                      replaced -A by -g and -g by -G
109                      added 1-connected and 2-connected (-c and -x)
110                      added 3-connected polytopes (-p)
111                      added -s for sparse6 output
112                      many small changes
113                      -- making 2.0
114         1-Sep-1999 : massive changes, including:
115                      added minimum degree 4 case (-m4 and -c4)
116                      added eulerian (dual bipartite) case (-b and -bc4)
117                      added polygon triangulations (-P)
118                      made some statistics optional (-v)
119                      -- making 3.0
120         2-Jul-2000 : fixed an error causing problems for minimum
121                      degree 5 on 26 or more vertices.  Many thanks
122                      to Thom Sulanke for finding it.  (Two changes in
123                      scansimple().)
124                      -- making 3.1
125         5-Jul-2000 : removed some useless code from scansimple()
126 
127        11-Apr-2001 : added code for -c1 and -c2.
128                      added -m5 native support (min5 plugin now obsolete)
129                      added -q for quadrangulations
130 		     improved polytope generation
131                      sparse6 output now represents loops only once
132 		     revised output format for -v
133                      -- making 4.0
134 
135        20-Jul-2001 : extended make_dual() to set facesize[] (note that
136                      make_dual() is not actually used, but may be
137                      useful for plug-ins)
138 
139        30-Aug-2001 : avoided all possible reads from elements outside arrays
140 		     (no known problem occured for distributed editions)
141 
142         5-Oct-2001 : corrected -m5 splitting (but it was probably not wrong)
143 
144        27-Oct-2001 : removed quadrangulations warning (now proved!)
145 
146        21-Nov-2001 : make quadrangulations from pseudo-double wheels
147 		     added -qc2
148 
149        23-Nov-2001 : added -qc4
150 
151         2-Dec-2001 : added -qc2m2
152 
153         8-Mar-2002 : added FAST_FILTER_* hooks
154 		     improved switch checking
155 		     added HELPMESSAGE option
156 
157         3-Oct-2004 : added PRE_FILTER_DISK
158 
159        27-Jul-2005 : added "void" prototypes, make CPUTIME more robust
160                      -- making 4.1
161 
162         3-Aug-2005 : added -V
163 
164        13-Mar-2007 : some warnings removed, added dummy function to
165                      avoid warnings of unused functions
166 
167        28-Jul-2007 : added -E for edge_code output
168 
169         2-Aug-2007 : added -bp for bipartite graphs
170                    : added general planar graphs (-p) of 2 and 3 vertices
171 
172        19-Feb-2008 : fixed -pc1x and -pc2x
173 
174        21-Feb-2008 : slightly improved -p for minimal edge counts
175                    : -p rejects some impossible edge counts with error msg
176 
177         2-May-2009 : fix incorrect connectivity computation in -p and -pb,
178 		       only known problems were with -c1x, -c2x and statistics
179                        reported by -v
180                      -- making 4.4
181 
182         2-Sep-2011 : also apply FAST_FILTER_* to starting graphs  (all uses
183 		       need checking against code as more than one filter
184 		       might need defining)
185                      -- making 4.5
186 
187        19-Sep-2011 : don't use rightface field in output routines, to avoid
188                      confusing generators and filters
189 
190         7-Mar-2014 : add -A for Appolonian networks
191 
192         2-Oct-2015 : add -pc4
193                      -- making 5.0
194 
195        28-Feb-2018 : Move secret -2 to public -X, which increases the
196                        splitting level by 1.
197                      Increase default splitting levels for most options.
198 		     Fix -m4c3x, which didn't work as advertised.
199 		     Add -T for double code output.
200 		     Fixed the group of the gyro (triangulation with
201                         three vertices and one loop)
202 		     -- making 5.1
203 
204         1-Jul-2021 : forbid -c4x and -c5x, which never meant anything
205                    : Use long long for counters
206                      -- making 5.2
207 
208 **************************************************************************/
209 
210 #include <stdio.h>
211 
212 #if __STDC__
213 #include <stdlib.h>
214 #include <errno.h>
215 #else
216 extern int errno;
217 #endif
218 
219 #include <string.h>
220 #include <limits.h>
221 
222 #define CPUTIME 1          /* Whether to measure the cpu time or not */
223 
224 #if CPUTIME
225 #include <sys/times.h>
226 #include <time.h>
227 #if !defined(CLK_TCK) && !defined(_SC_CLK_TCK)
228 #include <unistd.h>
229 #endif
230 #if !defined(CLK_TCK) && defined(_SC_CLK_TCK)
231 #define CLK_TCK sysconf(_SC_CLK_TCK)
232 #endif
233 #if !defined(CLK_TCK) && defined(CLOCKS_PER_SEC)
234 #define CLK_TCK CLOCKS_PER_SEC
235 #endif
236 #if !defined(CLK_TCK)
237 #define CLK_TCK 60     /* If the CPU time stated by the program appears to be
238 		       out by a constant ratio, the most likely explanation
239                        is that the code got to this point but 60 is the wrong
240                        guess.  Other common values are 100 and 1000. */
241 #endif
242 #endif
243 
244 #ifndef MAXN
245 #define MAXN 64            /* the maximum number of vertices; see above */
246 #endif
247 #define MAXE (6*MAXN-12)   /* the maximum number of oriented edges */
248 #define MAXF (2*MAXN-4)    /* the maximum number of faces */
249 
250 typedef struct e /* The data type used for edges */
251 {
252     int start;         /* vertex where the edge starts */
253     int end;           /* vertex where the edge ends */
254     int rightface;     /* face on the right side of the edge
255                           note: only valid if make_dual() called */
256     struct e *prev;    /* previous edge in clockwise direction */
257     struct e *next;    /* next edge in clockwise direction */
258     struct e *invers;  /* the edge that is inverse to this one */
259     struct e *min;     /* the least of e and e->invers */
260     int mark,index,rf;    /* three ints for temporary use;
261 			  rf is only for the printing routines;
262                           Only access mark via the MARK macros. */
263     int left_facesize; /* size of the face in prev-direction of the edge.
264         		  Only used for -p option. */
265 } EDGE;
266 
267 typedef struct
268 {
269     EDGE *e1,*e2,*e3;
270 } triangle;
271 
272 #undef FALSE
273 #undef TRUE
274 #define FALSE 0
275 #define TRUE  1
276 
277 /* Global variables */
278 
279 static char *outfilename;  /* name of output file (NULL for stdout) */
280 static FILE *outfile;      /* output file for graphs */
281 static FILE *msgfile;      /* file for informational messages */
282 
283 static int maxnv;          /* order of output graphs */
284 static int res,mod;        /* res/mod from command line (default 0/1) */
285 static int splitlevel,
286            splitcount;     /* used for res/mod splitting */
287 #ifdef PLUGIN
288 static int splithint = -1; /* used by plugins to set splitting level */
289 #endif
290 static int minconnec;      /* lower bound on minimum connectivity */
291 static int minpolyconnec;  /* lower bound on minumum connectivity for
292 			      polytopes.  Defaults to same as minconnec. */
293 static int xconnec;        /* Value of connectivity appropriate for -x.
294                               The same as either minconnec or minpolyconnec. */
295 static int edgebound[2];   /* edge count min,max for polytopes */
296 static int maxfacesize;    /* maximum face size for polytopes */
297 
298 static int polygonsize;    /* polygon size for -P.
299                               -1 means -P is absent
300                                0 means size is unrestricted */
301 
302 static int minimumdeg;     /* lower bound on minimum degree.
303                               -1 means nothing specified */
304 static int minpolydeg;     /* lower bound on minimum degree for polytopes.
305                               -1 will cause it to be reset to the same as
306                               minimumdeg, but plugins can set it otherwise. */
307 
308 static int aswitch,        /* presence of command-line switches */
309 	   Aswitch,
310 	   bswitch,
311            gswitch,
312            sswitch,
313 	   Eswitch,
314 	   Tswitch,
315            hswitch,
316            dswitch,
317            Gswitch,
318            oswitch,
319            qswitch,
320            tswitch,
321 	   pswitch,
322            uswitch,
323            vswitch,
324            Vswitch,
325            xswitch,
326 	   Xswitch;
327 
328 static int zeroswitch;     /* Undocumented option -0, writes digits */
329 static int oneswitch;      /* Undocumented option -1, implies -0 */
330 static int needgroup;      /* Is group needed at end of scansimple()
331 			      and similar routines? */
332 static int gotone_nbop;    /* Used only by got_one() */
333 static int gotone_nbtot;
334 
335 static int dosummary;      /* used by plugin */
336 static char *cmdname;      /* points to arg[0] */
337 
338 /* The variables below are used at each level of the iteration,
339    updating and restoring as we move up and down the search tree */
340 
341 static int nv;             /* number of vertices; they are 0..nv-1 */
342 static int ne;             /* number of directed edges (at most 6*nv-12) */
343 
344 #define NUMEDGES (24+70*MAXN)
345 static EDGE edges[NUMEDGES];
346 
347 #define init_edge edges
348 #define STAR3(n) (edges + 6 + ((n)<<3))
349 #define STAR4(n) (edges + 6 + 8*MAXN + ((n)<<3))
350 #define STAR5(n) (edges + 6 + 16*MAXN + ((n)<<4))
351 
352 #define P_op(n) (edges + 24 + 12*(n))
353 #define Q_op(n) (edges + 24 + 12*MAXN + 6*(n))
354 
355 #define four_op(n) (edges+6*(n))
356 #define five_op(n) (edges + 6*MAXN + 6*(n))
357 #define S_op(n) (edges + 12*MAXN + 18*(n))
358 
359 #define min5_a(n) (edges - 12 + 6*(n))
360 /* edges + 60 + 6*(n) - 12*6 since the smallest n for which it is possibly
361    called is n=12 and then it should start at edge 60 */
362 #define min5_b0(n) (edges - 156 + 6*MAXN + 12*(n))
363 /* edges - 12 + 6*MAXN + 12*(n) - 12*12, again since the smallest
364    possible n is 12 */
365 #define min5_b1(n) (edges - 300 + 18*MAXN + 12*(n))
366 /* edges - 156 + 18*MAXN + 12*(n) - 12*12 */
367 #define min5_c(n) (edges - 780 + 30*MAXN + 40*(n))
368 /* edges - 300 + 30*MAXN + 40*(n) - 12*40 */
369 
370 #define quadr_P0(n) (edges -8 + 4*MAXN + 4*(n))
371 /* The smallest n for which it is called is 3. Then it should start at entry
372    edges +4 + 4*MAXN -- right AFTER the edges for quadr_P1(n) which is
373    used in the same run. */
374 #define quadr_P1(n) (edges +4 + 4*(n))
375 /* edges + 24 + 4*(n) - 5*4 since the smallest n for which it is possibly
376    called is n=5  and then it should start at edge 24 */
377 #define quadr_P2(n) (edges - 60 + 4*MAXN + 8*(n))
378 /* edges +4 + 4*MAXN + 8*(n) - 8*8, again since the smallest
379    possible n is 8 */
380 #define quadr_P3(n) (edges - 188 + 12*MAXN + 16*(n))
381 /* edges - 60 + 12*MAXN + 16*(n) - 8*16 */
382 
383 static int degree[MAXN];   /* the degrees of the vertices */
384 static EDGE *firstedge[MAXN]; /* pointer to arbitrary edge out of vertex i. */
385   /* This pointer may change during the run, so all one can rely on is that
386      at any point it is "some" edge out of i */
387 
388 static EDGE *facestart[MAXF]; /* an edge in the clockwise orientation of
389                                  each face.  Only valid when computed. */
390 static int facesize[MAXF]; /* size of each face.  Only valid when computed. */
391 
392 static EDGE *numbering[2*MAXE][MAXE];
393   /* holds numberings produced by canon() or canon_edge() */
394 static EDGE *saved_numbering[2*MAXE][MAXE];
395   /* a copy of numbering used by scanordloops() */
396 
397 /* The following packed adjacency matrix is used for triangulations
398    of minconnec < 3. */
399 
400 static long am[MAXN];
401 #define BIT(i) (1L << (i))
402 #define ISADJ(i,j) (am[i] & BIT(j))
403 
404 /* The following unpacked adjacency matrix is used for general planar
405    graphs of connectivity 1 and 2. */
406 
407 static char am2[MAXN][64];
408 #define AMADDEDGE(i,j) { am2[i][j] = am2[j][i] = 1; }
409 #define AMDELEDGE(i,j) { am2[i][j] = am2[j][i] = 0; }
410 #define ISEQADJ(i,j) (am2[i][j] != 0)
411 #define ISNEQADJ(i,j) (am2[i][j] == 0)
412 
413 static EDGE *doubles[MAXE];  /* holds edges with parallel mates */
414 
415 #define PCODE ">>planar_code<<"
416 #define PCODELEN (sizeof(PCODE)-1)    /* "-1" to avoid the null */
417 #define ECODE ">>edge_code<<"
418 #define ECODELEN (sizeof(ECODE)-1)    /* "-1" to avoid the null */
419 #define G6CODE ">>graph6<<"
420 #define G6CODELEN (sizeof(G6CODE)-1)    /* "-1" to avoid the null */
421 #define S6CODE ">>sparse6<<"
422 #define S6CODELEN (sizeof(S6CODE)-1)    /* "-1" to avoid the null */
423 
424 static EDGE *code_edge = NULL;
425 /* if code_edge is not NULL, it is taken as the start for coding for
426    ASCII or planar_code. Otherwise firstedge[0] is the start. This
427    method implies comparatively few changes due to outputting
428    triangulations of disks.
429 
430    In case of triangulations of disks, *code_edge should be an edge
431    with the "outer" face on the left for the non-mirror case and on
432    the right for the mirror case to have the outer face left of 1->2.
433 
434    In case of dual output (mirror image or not), the face on the left
435    of *code_edge gets the number 1. So for duals of triangulations of
436    disks, handing in an edge with the disk on the right outputs the
437    "marked" vertex as 1.
438 */
439 
440 static int missing_vertex = -1;
441 /* The vertices are numbered 0..nv-1 if missing_vertex<0, and
442    0..missing_vertex-1,missing_vertex..nv otherwise.  This is
443    only used in the code for polygon triangulations. */
444 
445 static int outside_face_size;  /* Used for polygon triangulations. */
446 
447 static int zero[MAXN];   /* permanently 0 */
448 
449 /* In versions up to 5.0, large integers were represented as a
450  * structure of two longs, due to "long long" once being of
451  * uncertain availability.
452  *
453  * Starting at version 5.1, we assume "long long".
454  *
455  * All the macros are left here in case some code uses them,
456  * but plantri itself now uses only PRINTBIG.
457  *
458 */
459 
460 typedef unsigned long long bigint;
461 #define ZEROBIG(big) big = 0
462 #define ISZEROBIG(big) ((big) == 0)
463 #define SETBIG(big,value) big = (value)
464 #define ADDBIG(big,extra) big += (extra)
465 #define PRINTBIG(file,big) fprintf(file,"%llu",(big))
466 #define BIGTODOUBLE(big) ((double)(big))
467 #define SUMBIGS(big1,big2) big1 += (big2)
468 #define SUBBIGS(big1,big2) big1 -= (big2)
469 #define ISEQBIG(big1,big2) ((big1) == (big2))
470 
471 static bigint nout[6];      /* counts of output graphs, per connectivity */
472 static bigint nout_op[6];   /* counts of output graphs, per connectivity, OP */
473 static bigint nout_e[MAXE/2+1];  /* .. per undirected edge number */
474 static bigint nout_e_op[MAXE/2+1];  /* .. per undirected edge number, OP */
475 static bigint nout_p[MAXN+1];  /* .. per polygon size */
476 static bigint nout_p_op[MAXN+1];  /* .. per polygon size, OP */
477 static bigint totalout;       /* Sum of nout[] (always) */
478 static bigint totalout_op;    /* Sum of nout_op[] (only if -o) */
479 static bigint nout_V;        /* Deletions due to -V */
480 
481 static char outtypename[50];  /* How to describe output objects */
482 
483 #ifdef STATS    /* optional statistics collection */
484 static bigint numrooted;  /* rooted maps */
485 static bigint ntriv;      /* counter of those with trivial groups
486     (needs -G or something that implies it, like -o, -p, -P)  */
487 static bigint nummindeg[6];  /* count according to min degree */
488 static bigint numbigface[MAXN+1];  /* count according to outside face */
489 static bigint numrooted_e[MAXE/2+1];  /* rooted maps per undirected edges */
490 #endif
491 #if defined(STATS2) && defined(STATS)   /* even more statistics collection */
492 static bigint numtwos[MAXN+1];   /* number of vertices of degree 2 */
493 #endif
494 
495 static int markvalue = 30000;
496 #define RESETMARKS {int mki; if ((markvalue += 2) > 30000) \
497        { markvalue = 2; for (mki=0;mki<NUMEDGES;++mki) edges[mki].mark=0;}}
498 #define MARK(e) (e)->mark = markvalue
499 #define MARKLO(e) (e)->mark = markvalue
500 #define MARKHI(e) (e)->mark = markvalue+1
501 #define UNMARK(e) (e)->mark = markvalue-1
502 #define ISMARKED(e) ((e)->mark >= markvalue)
503 #define ISMARKEDLO(e) ((e)->mark == markvalue)
504 #define ISMARKEDHI(e) ((e)->mark > markvalue)
505 
506 /* and the same for vertices */
507 
508 static int markvalue_v = 30000;
509 static int marks__v[MAXN];
510 #define RESETMARKS_V {int mki; if ((++markvalue_v) > 30000) \
511        { markvalue_v = 1; for (mki=0;mki<MAXN;++mki) marks__v[mki]=0;}}
512 #define UNMARK_V(x) (marks__v[x] = 0)
513 #define ISMARKED_V(x) (marks__v[x] == markvalue_v)
514 #define MARK_V(x) (marks__v[x] = markvalue_v)
515 
516 static EDGE *inmaxface[MAXN*MAXN-3*MAXN/2];   /* Used for polytope
517   generation - lists edges whose left face is maximum size */
518 
519 static void (*write_graph)(FILE*,int);
520 static void (*write_dual_graph)(FILE*,int);
521 
522 #define CHECKSWITCH(name) check_switch(name,ok_switches)
523 #define OK_SWITCHES(name) ok_switches[(unsigned char)(name)]
524 #define INCOMPAT(cond,x,y) if (cond) \
525   {fprintf(stderr,">E %s: %s and %s are incompatible\n",cmdname,x,y); exit(1);}
526 #define CHECKRANGE(var,varname,lo,hi) if ((var)<(lo)||(var)>(hi)) \
527   {fprintf(stderr,">E %s: the value of %s must be ",cmdname,varname); \
528   if ((lo)==(hi)) \
529     fprintf(stderr,"%d\n",lo); else fprintf(stderr,"%d..%d\n",lo,hi); \
530     exit(1);}
531 #define PERROR(cond,msg) if (cond) \
532    {fprintf(stderr,">E %s: %s\n",cmdname,msg); exit(1);}
533 
534 #define BOOLSWITCH(name,var)  \
535     else if (arg[j]==name) {CHECKSWITCH(name); var = TRUE;}
536 #define COUNTSWITCH(name,var)  \
537     else if (arg[j]==name) {CHECKSWITCH(name); ++var;}
538 #define INTSWITCH(name,var)  \
539     else if (arg[j]==name) {CHECKSWITCH(name); var = getswitchvalue(arg,&j);}
540 
541 #define SECRET_SWITCHES "01"
542 
543 #define MAX(x,y) ((x)<(y) ? (y) : (x))
544 #define MIN(x,y) ((x)>(y) ? (y) : (x))
545 
546 #ifdef SPLITTEST
547 static bigint splitcases;
548 #endif
549 
550 /**************************************************************************/
551 
552 /* Include optional file for special processing. */
553 
554 #ifdef PLUGIN
555 #include PLUGIN
556 #endif
557 
558 #ifdef PRE_FILTER
559 Error - Trying to use an obsolete plugin
560 #endif
561 
562 /**************************************************************************/
563 
564 static int
565 maxdegree(void)
566 
567 /* Find the maximum degree */
568 
569 {
570     int maxd,i;
571 
572     maxd = 0;
573     for (i = 0; i < nv; ++i)
574 	if (degree[i] > maxd) maxd = degree[i];
575 
576     return maxd;
577 }
578 
579 /**************************************************************************/
580 
581 static void
show_group(FILE * f,int nbtot,int nbop)582 show_group(FILE *f, int nbtot, int nbop)
583 
584 /* Display the group stored in the usual place */
585 
586 {
587     EDGE **nb,**nblim;
588     int i;
589 
590     fprintf(f,"nv=%d ne=%d nbtot=%d nbop=%d\n",nv,ne,nbtot,nbop);
591 
592     if (nbtot == 1) return;
593 
594     nblim = (EDGE**)numbering[nbtot];
595     for (nb = (EDGE**)numbering[0]; nb < nblim; nb += MAXE)
596     {
597 	for (i = 0; i < ne; ++i)
598 	    fprintf(f," %x-%x",nb[i]->start,nb[i]->end);
599 	fprintf(f,"\n");
600     }
601 }
602 
603 /**************************************************************************/
604 
605 /* Routines for extending and reducing a triangulation.
606    General principle:  extendx(e); reducex(e)  will extend by one
607    vertex of degree x (x=3,4,5) then reduce it to the original graph.
608    The final graph is exactly the same as the original
609    (including pointer values) except that possibly the values of
610    firstedge[] might be different.
611 */
612 
613 static void
extend3(EDGE * e)614 extend3(EDGE *e)
615 
616 /* inserts a vertex with valence 3 in the triangle on the right hand
617    side (->next direction) of the edge e */
618 {
619     register EDGE *work1, *work2, *work3;
620 
621     work1 = STAR3(nv);
622     work2 = work1+1;
623     work3 = work2+1;
624     firstedge[nv] = work3+1;
625 
626 /* work1 starts at the beginning of e: */
627 
628     work1->start = work1->invers->end = e->start;
629     e->next->prev = work1;
630     work1->next = e->next;
631     work1->prev = e;
632     e->next = work1;
633     (degree[e->start])++;
634 
635 /* Now go one edge further around the triangle and the same once more */
636 
637     e = e->invers->prev;
638 
639     work2->start = work2->invers->end = e->start;
640     e->next->prev = work2;
641     work2->next = e->next;
642     work2->prev = e;
643     e->next = work2;
644     (degree[e->start])++;
645 
646     e = e->invers->prev;
647 
648     work3->start = work3->invers->end = e->start;
649     e->next->prev = work3;
650     work3->next = e->next;
651     work3->prev = e;
652     e->next = work3;
653     (degree[e->start])++;
654 
655     degree[nv] = 3;
656 
657 /* Now I have 6 edges and one vertex more */
658 
659     ne += 6;
660     nv++;
661 }
662 
663 /****************************************/
664 
665 static void
reduce3(EDGE * e)666 reduce3(EDGE *e)
667 
668 /* deletes a vertex with valence 3 in the triangle on the right hand side
669  (->next-direction) of the edge e. It is not checked whether the vertex
670  really has valence 3 -- this has to be made sure in advance      */
671 {
672  /* It might be that one of the edges leading to the new vertex now is
673        an entry of firstedge[] */
674 
675  /* If (firstedge[e->start]==e->next) would take too much time, so just*/
676 
677     firstedge[e->start] = e;
678     e->next = e->next->next; e->next->prev = e;
679     (degree[e->start])--;
680     e = e->invers;
681 
682     firstedge[e->start] = e;
683  /* Now delete on the ->prev side */
684     e->prev = e->prev->prev; e->prev->next = e;
685     (degree[e->start])--;
686     e = e->prev->invers;
687 
688     firstedge[e->start] = e;
689  /* Again on the ->prev side: */
690     e->prev = e->prev->prev; e->prev->next = e;
691     (degree[e->start])--;
692 
693     nv--;
694     ne -= 6;
695 }
696 
697 /************************************************************************/
698 
699 static void
extend4(EDGE * e,EDGE * list[])700 extend4(EDGE *e, EDGE *list[])
701 
702 /* Deletes e->next and its inverse and puts a valence 4 vertex into the
703    resulting square.
704    In list[0..1] the deleted edges are stored. This list must be handed
705    to reduce4() */
706 {
707     register EDGE *work1, *work2, *work3, *work4;
708 
709     list[0] = e->next; list[1] = e->next->invers;
710 
711     work1 = STAR4(nv);
712     work2 = work1+1;
713     work3 = work2+1;
714     work4 = work3+1;
715     firstedge[nv] = work4+1;;
716 
717     firstedge[e->start] = e;
718  /* make sure firstedge points at a valid edge afterwards */
719 
720  /* work1 starts at the beginning of e: */
721 
722     work1->start = work1->invers->end = e->start;
723     work1->next = e->next->next;
724     work1->next->prev = work1;
725     work1->prev = e;
726     e->next = work1;
727  /* the degree of e->start doesn't change */
728 
729  /* Now go one edge further around the square: */
730 
731     e = e->invers->prev;
732 
733     work2->start = work2->invers->end = e->start;
734     e->next->prev = work2;
735     work2->next = e->next;
736     work2->prev = e;
737     e->next = work2;
738     (degree[e->start])++;
739 
740  /* Now we have one edge to jump about again: */
741     e = e->invers->prev->prev;
742 
743     firstedge[e->start] = e;
744  /* Again an edge is deleted... */
745 
746     work3->start = work3->invers->end = e->start;
747     work3->next = e->next->next;
748     work3->next->prev = work3;
749     work3->prev = e;
750     e->next = work3;
751  /* the degree of e->start doesn't change */
752 
753  /* Now go again one edge further around the square: */
754 
755     e = e->invers->prev;
756 
757     work4->start = work4->invers->end = e->start;
758     e->next->prev = work4;
759     work4->next = e->next;
760     work4->prev = e;
761     e->next = work4;
762     (degree[e->start])++;
763 
764     degree[nv] = 4;
765 
766  /* Now I have 6 edges and one vertex more */
767 
768     ne += 6;
769     nv++;
770 }
771 
772 /**************************/
773 
774 static void
reduce4(EDGE * e,EDGE * list[])775 reduce4(EDGE *e, EDGE *list[])
776 
777 /* The inverse operation to extend4().
778    Deletes the vertex with valence 4 in the triangle on the right hand side
779    (->next-direction) of the edge e that is not contained in e. It is not
780    checked whether the vertex really has valence 4 -- this has to be made
781    sure in advance. The vector list[] must contain the edges deleted before.
782    It might be that one of the edges leading to the new vertex now is
783    an entry of firstedge[] */
784 {
785 
786     firstedge[e->start] = e;
787 
788     list[0]->next->prev = list[0];
789     e->next = list[0];
790     e = e->invers;
791 
792     firstedge[e->start] = e;
793 /* Now delete on the ->prev side */
794     e->prev = e->prev->prev; e->prev->next = e;
795     (degree[e->start])--;
796     e = e->prev->invers;
797 
798     firstedge[e->start] = e;
799 /* Again on the ->prev side: */
800     list[1]->prev->next = list[1];
801     e->prev = list[1];
802 
803     e = list[1]->prev->invers;
804     firstedge[e->start] = e;
805     e->prev = e->prev->prev; e->prev->next = e;
806     (degree[e->start])--;
807 
808     nv--;
809     ne -= 6;
810 }
811 
812 /**********************************************************************/
813 
814 static void
extend5(EDGE * e,EDGE * list[])815 extend5(EDGE *e, EDGE *list[])
816 
817 /* Deletes e->next, e->next->next and their inverse and puts a valence
818    5 vertex into the resulting pentagon.
819    In list[0..3] the deleted edges are stored. This list must be handed
820    to reduce5() */
821 {
822     register EDGE *work1, *work2, *work3, *work4, *work5;
823 
824     list[0] = e->next; list[1] = e->next->invers;
825     list[2] = e->next->next; list[3] = list[2]->invers;
826 
827     work1 = STAR5(nv);
828     work2 = work1+1;
829     work3 = work2+1;
830     work4 = work3+1;
831     work5 = work4+1;
832     firstedge[nv] = work5+1;;
833 
834     firstedge[e->start] = e;
835 /* make sure firstedge points at a valid edge afterwards */
836 
837 /* work1 starts at the beginning of e: */
838 
839     work1->start = work1->invers->end = e->start;
840     work1->next = e->next->next->next;
841     work1->next->prev = work1;
842     work1->prev = e;
843     e->next = work1;
844     (degree[e->start])--;
845 
846 /* Now go one edge further around the pentagon: */
847     e = e->invers->prev;
848 
849     work2->start = work2->invers->end = e->start;
850     e->next->prev = work2;
851     work2->next = e->next;
852     work2->prev = e;
853     e->next = work2;
854     (degree[e->start])++;
855 
856 /* Now go one edge further around the pentagon jumping over one edge: */
857 
858     e = e->invers->prev->prev;
859 
860     firstedge[e->start] = e;
861 /* here also an edge is deleted */
862 
863     work3->start = work3->invers->end = e->start;
864     work3->next = e->next->next;
865     work3->next->prev = work3;
866     work3->prev = e;
867     e->next = work3;
868 /* the degree of e->start doesn't change */
869 
870 /* Again go one edge further around the pentagon jumping over one edge: */
871 
872     e = e->invers->prev->prev;
873 
874     firstedge[e->start] = e;
875 /* here also an edge is deleted */
876 
877     work4->start = work4->invers->end = e->start;
878     work4->next = e->next->next;
879     work4->next->prev = work4;
880     work4->prev = e;
881     e->next = work4;
882 /* the degree of e->start doesn't change */
883 
884 /* Finally go one edge further around the pentagon: */
885     e = e->invers->prev;
886 
887     work5->start = work5->invers->end = e->start;
888     e->next->prev = work5;
889     work5->next = e->next;
890     work5->prev = e;
891     e->next = work5;
892     (degree[e->start])++;
893 
894     degree[nv] = 5;
895 
896 /* Now I have 6 edges and one vertex more */
897 
898     ne += 6;
899     nv++;
900 }
901 
902 /*****************************/
903 
904 static void
reduce5(EDGE * e,EDGE * list[])905 reduce5(EDGE *e, EDGE *list[])
906 
907 /* The inverse operation to extend5().
908    Deletes the vertex with valence 5 at the end of e->next. It is not
909    checked whether the vertex really has valence 5 -- this has to be made
910    sure in advance. The vector list[] must contain the edges deleted before.
911    It might be that one of the edges leading to the new vertex now is
912    an entry of firstedge[] */
913 {
914     firstedge[e->start] = e;
915 
916     e->next = list[0];
917     list[2]->next->prev = list[2];
918     (degree[e->start])++;
919 
920     e = e->invers;
921 
922 /* Delete the edge on the prev side */
923     firstedge[e->start] = e;
924     e->prev = e->prev->prev; e->prev->next = e;
925     (degree[e->start])--;
926 
927     e = e->prev->invers;
928 
929     firstedge[e->start] = e;
930 /* Delete the edge and insert the old edge: */
931     e->prev = list[1];
932     list[1]->prev->next = list[1];
933 
934     e = e->prev->prev->invers;
935 
936     firstedge[e->start] = e;
937 /* Delete the edge and insert the old edge: */
938     e->prev = list[3];
939     list[3]->prev->next = list[3];
940 
941     e = e->prev->prev->invers;
942 
943     firstedge[e->start] = e;
944     e->prev = e->prev->prev; e->prev->next = e;
945     (degree[e->start])--;
946 
947     nv--;
948     ne-=6;
949 }
950 
951 /*************************************************************************/
952 
953 static void
switch_edge(EDGE * e)954 switch_edge(EDGE *e)
955 
956 /* switches edge e -- that is: removes e and puts in the other diagonal in
957    the 4-gon given by the two triangles adjacent to e */
958 {
959     register EDGE *work1, *work2;
960 
961 
962 /* closing the gap when e is removed */
963     firstedge[e->start]=e->next;
964     e->prev->next=e->next;
965     e->next->prev=e->prev;
966     (degree[e->start])--;
967 
968 /* rotating e */
969     work1=e->next->invers; work2=work1->next;
970     e->start=work1->start; e->end=e->prev->end;
971     e->prev=work1; e->next=work2;
972     work1->next=e; work2->prev=e;
973     (degree[work1->start])++;
974 
975 /* Now doing the same with e->invers */
976 
977     e=e->invers;
978     firstedge[e->start]=e->next;
979     e->prev->next=e->next;
980     e->next->prev=e->prev;
981     (degree[e->start])--;
982     work1=e->next->invers; work2=work1->next;
983     e->start=work1->start; e->end=e->prev->end;
984     e->prev=work1; e->next=work2;
985     work1->next=e; work2->prev=e;
986     (degree[work1->start])++;
987 }
988 
989 /***************************************************************************/
990 
991 static void
switch_edge_back(EDGE * e)992 switch_edge_back(EDGE *e)
993 
994 /* Although switching twice is the identity on the graph, it is not on the
995    data structure used. In the extend() routines the special order given
996    in the initialisation is used */
997 {
998     register EDGE *work1, *work2;
999 
1000 /* closing the gap when e is removed */
1001     firstedge[e->start]=e->next;
1002     e->prev->next=e->next;
1003     e->next->prev=e->prev;
1004     (degree[e->start])--;
1005 
1006 /* rotating e */
1007     work2=e->prev->invers; work1=work2->prev;
1008     e->start=work1->start; e->end=e->next->end;
1009     e->prev=work1; e->next=work2;
1010     work1->next=e; work2->prev=e;
1011     (degree[work1->start])++;
1012 
1013 /* Now doing the same with e->invers */
1014 
1015     e=e->invers;
1016     firstedge[e->start]=e->next;
1017     e->prev->next=e->next;
1018     e->next->prev=e->prev;
1019     (degree[e->start])--;
1020 
1021     work2=e->prev->invers; work1=work2->prev;
1022     e->start=work1->start; e->end=e->next->end;
1023     e->prev=work1; e->next=work2;
1024     work1->next=e; work2->prev=e;
1025     (degree[work1->start])++;
1026 }
1027 
1028 /**************************************************************************/
1029 
1030 static int
testcanon(EDGE * givenedge,int representation[],int colour[])1031 testcanon(EDGE *givenedge, int representation[], int colour[])
1032 
1033 /* Tests whether starting from a given edge and constructing the code in
1034    "->next" direction, an automorphism or even a better representation
1035    can be found. Returns 0 for failure, 1 for an automorphism and 2 for
1036    a better representation.  This function exits as soon as a better
1037    representation is found. A function that computes and returns the
1038    complete better representation can work pretty similar.*/
1039 {
1040     EDGE *temp, *run;
1041     EDGE *startedge[MAXN+1]; /* startedge[i] is the starting edge for
1042                         exploring the vertex with the number i+1 */
1043     int number[MAXN], i;   /* The new numbers of the vertices, starting
1044                         at 1 in order to have "0" as a possibility to
1045                         mark ends of lists and not yet given numbers */
1046     int last_number, actual_number, vertex;
1047 
1048     for (i = 0; i < nv; i++) number[i] = 0;
1049 
1050     number[givenedge->start] = 1;
1051 
1052     if (givenedge->start != givenedge->end) /* no loop start */
1053       {
1054 	number[givenedge->end] = 2;
1055 	last_number = 2;
1056 	startedge[1] = givenedge->invers;
1057       }
1058     else last_number = 1 ;
1059 
1060     actual_number = 1;
1061     temp = givenedge;
1062 
1063 /* A representation is a clockwise ordering of all neighbours ended with a 0.
1064    The neighbours are numbered in the order that they are reached by the BFS
1065    procedure. In case a vertex is reached for the first time, not the (new)
1066    number of the vertex is listed, but its colour. When the list around a
1067    vertex is finished, it is ended with a 0. Since the colours can be
1068    distinguished from the vertices (requirement for the colour function), the
1069    adjacency list can be reconstructed: Every time a colour is listed, its
1070    number would be the smallest number not given yet.
1071    Since the edges when a vertex is reached for the first time are remembered,
1072    for these edges we in fact have more than just the vertex information -- for
1073    these edges we also have the exact information which edge occurs in the
1074    cyclic order. This makes the routine work also for double edges.
1075 
1076    Since every representation starts with the colour of vertex 2, which is
1077    the same colour all the time, we do not have to store that.
1078 
1079    In case of a loop as the starting point, the colour of 1 is omitted.
1080    Nevertheless also in this case it cannot be mixed up with a non-loop
1081    starting point, since the number of times a colour occurs is larger
1082    for loop starters than for non-loop starters.
1083 
1084    Every first entry in a new clockwise ordering (the starting point of the
1085    edge it was numbered from is determined by the entries before (the first
1086    time it occurs in the list to be exact), so this is not given either.
1087    The K4 could be denoted  c3 c4 0 4 3 0 2 3 0 3 2 0 if ci is the colour
1088    of vertex i.  Note that the colour of vertex 1 is -- by definition --
1089    always the smallest one */
1090 
1091     while (last_number < nv)
1092     {
1093         for (run = temp->next; run != temp; run = run->next)
1094     /* this loop marks all edges around temp->origin. */
1095           { vertex = run->end;
1096             if (!number[vertex])
1097               { startedge[last_number] = run->invers;
1098                 last_number++; number[vertex] = last_number;
1099                 vertex = colour[vertex]; }
1100             else vertex = number[vertex];
1101             if (vertex > (*representation)) return 0;
1102             if (vertex < (*representation)) return 2;
1103             representation++;
1104           }
1105    /* check whether representation[] is also at the end of a cyclic list */
1106         if ((*representation) != 0) return 2;
1107         representation++;
1108    /* Next vertex to explore: */
1109         temp = startedge[actual_number];  actual_number++;
1110     }
1111 
1112     while (actual_number <= nv)
1113                 /* Now we know that all numbers have been given */
1114     {
1115         for (run = temp->next; run != temp; run = run->next)
1116     /* this loop marks all edges around temp->origin. */
1117           {
1118             vertex = number[run->end];
1119             if (vertex > (*representation)) return 0;
1120             if (vertex < (*representation)) return 2;
1121             representation++;
1122           }
1123    /* check whether representation[] is also at the end of a cyclic list */
1124         if ((*representation) != 0) return 2;
1125         representation++;
1126    /* Next vertex to explore: */
1127         temp = startedge[actual_number];  actual_number++;
1128     }
1129 
1130     return 1;
1131 }
1132 
1133 /*****************************************************************************/
1134 
1135 static int
testcanon_mirror(EDGE * givenedge,int representation[],int colour[])1136 testcanon_mirror(EDGE *givenedge, int representation[], int colour[])
1137 
1138 /* Tests whether starting from a given edge and constructing the code in
1139    "->prev" direction, an automorphism or even a better representation can
1140    be found. Comments see testcanon -- it is exactly the same except for
1141    the orientation */
1142 {
1143     EDGE *temp, *run;
1144     EDGE *startedge[MAXN+1];
1145     int number[MAXN], i;
1146     int last_number, actual_number, vertex;
1147 
1148     for (i = 0; i < nv; i++) number[i] = 0;
1149 
1150     number[givenedge->start] = 1;
1151 
1152     if (givenedge->start != givenedge->end)
1153       {
1154 	number[givenedge->end] = 2;
1155 	last_number = 2;
1156 	startedge[1] = givenedge->invers;
1157       }
1158     else last_number = 1;
1159 
1160     actual_number = 1;
1161     temp = givenedge;
1162 
1163     while (last_number < nv)
1164     {
1165         for (run = temp->prev; run != temp; run = run->prev)
1166           { vertex = run->end;
1167             if (!number[vertex])
1168               { startedge[last_number] = run->invers;
1169                 last_number++; number[vertex] = last_number;
1170                 vertex = colour[vertex]; }
1171             else vertex = number[vertex];
1172             if (vertex > (*representation)) return 0;
1173             if (vertex < (*representation)) return 2;
1174             representation++;
1175           }
1176         if ((*representation) != 0) return 2;
1177         representation++;
1178         temp = startedge[actual_number];  actual_number++;
1179     }
1180 
1181     while (actual_number <= nv)
1182     {
1183         for (run = temp->prev; run != temp; run = run->prev)
1184           {
1185             vertex = number[run->end];
1186             if (vertex > (*representation)) return 0;
1187             if (vertex < (*representation)) return 2;
1188             representation++;
1189           }
1190         if ((*representation) != 0) return 2;
1191         representation++;
1192         temp = startedge[actual_number];  actual_number++;
1193     }
1194 
1195     return 1;
1196 }
1197 
1198 /****************************************************************************/
1199 
1200 static void
testcanon_first_init(EDGE * givenedge,int representation[],int colour[])1201 testcanon_first_init(EDGE *givenedge, int representation[], int colour[])
1202 
1203 /* Tests whether starting from a given edge and constructing the code in
1204    "->next" direction, an automorphism or even a better representation can
1205    be found. A better representation will be completely constructed and
1206    returned in "representation".  It works pretty similar to testcanon except
1207    for obviously necessary changes, so for extensive comments see testcanon */
1208 {
1209     register EDGE *run;
1210     register int vertex;
1211     EDGE *temp;
1212     EDGE *startedge[MAXN+1];
1213     int number[MAXN], i;
1214     int last_number, actual_number;
1215 
1216 
1217     for (i = 0; i < nv; i++) number[i] = 0;
1218 
1219     number[givenedge->start] = 1;
1220     if (givenedge->start != givenedge->end)
1221       {
1222 	number[givenedge->end] = 2;
1223 	last_number = 2;
1224 	startedge[1] = givenedge->invers;
1225       }
1226     else last_number = 1;
1227 
1228     actual_number = 1;
1229     temp = givenedge;
1230 
1231     while (last_number < nv)
1232     {
1233         for (run = temp->next; run != temp; run = run->next)
1234           { vertex = run->end;
1235             if (!number[vertex])
1236               { startedge[last_number] = run->invers;
1237                 last_number++; number[vertex] = last_number;
1238                 *representation = colour[vertex]; }
1239             else *representation = number[vertex];
1240             representation++;
1241           }
1242         *representation = 0;
1243         representation++;
1244         temp = startedge[actual_number];  actual_number++;
1245     }
1246 
1247     while (actual_number <= nv)
1248     {
1249         for (run = temp->next; run != temp; run = run->next)
1250           {
1251             *representation = number[run->end]; representation++;
1252           }
1253         *representation = 0;
1254         representation++;
1255         temp = startedge[actual_number];  actual_number++;
1256     }
1257 
1258     return;
1259 }
1260 
1261 /****************************************************************************/
1262 
1263 static void
testcanon_first_init_mirror(EDGE * givenedge,int representation[],int colour[])1264 testcanon_first_init_mirror(EDGE *givenedge, int representation[],
1265 			    int colour[])
1266 
1267 /* Tests whether starting from a given edge and constructing the code in
1268    "->prev" direction, an automorphism or even a better representation can
1269    be found. A better representation will be completely constructed and
1270    returned in "representation".  It works pretty similar to testcanon except
1271    for obviously necessary changes, so for extensive comments see testcanon */
1272 {
1273     register EDGE *run;
1274     register int vertex;
1275     EDGE *temp;
1276     EDGE *startedge[MAXN+1];
1277     int number[MAXN], i;
1278     int last_number, actual_number;
1279 
1280     for (i = 0; i < nv; i++) number[i] = 0;
1281 
1282     number[givenedge->start] = 1;
1283     if (givenedge->start != givenedge->end)
1284       {
1285 	number[givenedge->end] = 2;
1286 	last_number = 2;
1287 	startedge[1] = givenedge->invers;
1288       }
1289     else last_number = 1;
1290 
1291     actual_number = 1;
1292     temp = givenedge;
1293 
1294     while (last_number < nv)
1295     {
1296         for (run = temp->prev; run != temp; run = run->prev)
1297           { vertex = run->end;
1298             if (!number[vertex])
1299               { startedge[last_number] = run->invers;
1300                 last_number++; number[vertex] = last_number;
1301                 *representation = colour[vertex]; }
1302             else *representation = number[vertex];
1303             representation++;
1304           }
1305         *representation = 0;
1306         representation++;
1307         temp = startedge[actual_number];  actual_number++;
1308     }
1309 
1310     while (actual_number <= nv)
1311     {
1312         for (run = temp->prev; run != temp; run = run->prev)
1313           {
1314             *representation = number[run->end]; representation++;
1315           }
1316         *representation = 0;
1317         representation++;
1318         temp = startedge[actual_number];  actual_number++;
1319     }
1320 
1321     return;
1322 }
1323 
1324 /****************************************************************************/
1325 
1326 static int
testcanon_init(EDGE * givenedge,int representation[],int colour[])1327 testcanon_init(EDGE *givenedge, int representation[], int colour[])
1328 
1329 /* Tests whether starting from a given edge and constructing the code in
1330    "->next" direction, an automorphism or even a better representation can
1331    be found. A better representation will be completely constructed and
1332    returned in "representation".  It works pretty similar to testcanon except
1333    for obviously necessary changes, so for extensive comments see testcanon */
1334 {
1335     register EDGE *run;
1336     register int vertex;
1337     EDGE *temp;
1338     EDGE *startedge[MAXN+1];
1339     int number[MAXN], i;
1340     int better = 0; /* is the representation already better ? */
1341     int last_number, actual_number;
1342 
1343     for (i = 0; i < nv; i++) number[i] = 0;
1344 
1345     number[givenedge->start] = 1;
1346     if (givenedge->start != givenedge->end)
1347       {
1348 	number[givenedge->end] = 2;
1349 	last_number = 2;
1350 	startedge[1] = givenedge->invers;
1351       }
1352     else last_number = 1;
1353 
1354     actual_number = 1;
1355     temp = givenedge;
1356 
1357     while (last_number < nv)
1358     {
1359         for (run = temp->next; run != temp; run = run->next)
1360           { vertex = run->end;
1361             if (!number[vertex])
1362               { startedge[last_number] = run->invers;
1363                 last_number++; number[vertex] = last_number;
1364                 vertex = colour[vertex]; }
1365             else vertex=number[vertex];
1366             if (better) *representation = vertex;
1367              else { if (vertex > (*representation)) return 0;
1368                      else if (vertex < (*representation))
1369                        { better = 1; *representation = vertex; }
1370                   }
1371             representation++;
1372           }
1373         if ((*representation) != 0) { better = 1; *representation = 0; }
1374         representation++;
1375         temp = startedge[actual_number];  actual_number++;
1376     }
1377 
1378     while (actual_number <= nv)
1379     {
1380         for (run = temp->next; run != temp; run = run->next)
1381           { vertex = number[run->end];
1382             if (better) *representation = vertex;
1383             else
1384               {
1385                 if (vertex > (*representation)) return 0;
1386                 if (vertex < (*representation))
1387                   { better = 1; *representation = vertex; }
1388               }
1389             representation++;
1390           }
1391         if ((*representation) != 0) { better = 1; *representation = 0; }
1392         representation++;
1393         temp = startedge[actual_number];  actual_number++;
1394     }
1395 
1396     if (better) return 2;
1397     return 1;
1398 }
1399 
1400 /****************************************************************************/
1401 
1402 static int
testcanon_mirror_init(EDGE * givenedge,int representation[],int colour[])1403 testcanon_mirror_init(EDGE *givenedge, int representation[], int colour[])
1404 
1405 /* Tests whether starting from a given edge and constructing the code in
1406    "->prev" direction, an automorphism or even a better representation can
1407    be found. A better representation will be completely constructed and
1408    returned in "representation".  It works pretty similar to testcanon except
1409    for obviously necessary changes, so for extensive comments see testcanon */
1410 {
1411     EDGE *temp, *run;
1412     EDGE *startedge[MAXN+1];
1413     int number[MAXN], i;
1414     int better = 0; /* is the representation already better ? */
1415     int last_number, actual_number, vertex;
1416 
1417     for (i = 0; i < nv; i++) number[i] = 0;
1418 
1419     number[givenedge->start] = 1;
1420     if (givenedge->start != givenedge->end)
1421       {
1422 	number[givenedge->end] = 2;
1423 	last_number = 2;
1424 	startedge[1] = givenedge->invers;
1425       }
1426     else last_number = 1;
1427 
1428     actual_number = 1;
1429     temp = givenedge;
1430 
1431     while (last_number < nv)
1432     {
1433         for (run = temp->prev; run != temp; run = run->prev)
1434           { vertex = run->end;
1435             if (!number[vertex])
1436               { startedge[last_number] = run->invers;
1437                 last_number++; number[vertex] = last_number;
1438                 vertex = colour[vertex]; }
1439             else vertex=number[vertex];
1440             if (better) *representation = vertex;
1441             else { if (vertex > (*representation)) return 0;
1442                    else if (vertex < (*representation))
1443                      { better = 1; *representation = vertex; }
1444                  }
1445             representation++;
1446           }
1447         if ((*representation) != 0) { better = 1; *representation = 0; }
1448         representation++;
1449         temp = startedge[actual_number];  actual_number++;
1450     }
1451 
1452     while (actual_number <= nv)
1453     {
1454         for (run = temp->prev; run != temp; run = run->prev)
1455           { vertex = number[run->end];
1456             if (better) *representation = vertex;
1457             else
1458               {
1459                 if (vertex > (*representation)) return 0;
1460                 if (vertex < (*representation))
1461                   { better = 1; *representation = vertex; }
1462               }
1463             representation++;
1464           }
1465        if ((*representation) != 0) { better = 1; *representation = 0; }
1466        representation++;
1467        temp = startedge[actual_number];  actual_number++;
1468     }
1469 
1470     if (better) return 2;
1471     return 1;
1472 }
1473 
1474 /****************************************************************************/
1475 
1476 static void
construct_numb(EDGE * givenedge,EDGE * numbering[])1477 construct_numb(EDGE *givenedge, EDGE *numbering[])
1478 
1479 /* Starts at givenedge and writes the edges in the well defined order
1480    into the list.  Works like testcanon. Look there for comments. */
1481 {
1482     EDGE *temp, **tail, **limit, *run;
1483     EDGE *startedge[MAXN+1];
1484     int last_number, actual_number, vertex;
1485 
1486     RESETMARKS_V;
1487 
1488     tail = numbering;
1489     limit = numbering+ne-1;
1490 
1491     MARK_V(givenedge->start);
1492     if (givenedge->start != givenedge->end)
1493       {
1494 	MARK_V(givenedge->end);
1495 	last_number = 2;
1496 	startedge[1] = givenedge->invers;
1497       }
1498     else last_number = 1;
1499 
1500     actual_number = 1;
1501     temp = *tail = givenedge;
1502 
1503     while (last_number < nv)
1504     {
1505         for (run = temp->next; run != temp; run = run->next)
1506     /* this loop marks all edges around temp->origin. */
1507           { vertex = run->end;
1508             if (!ISMARKED_V(vertex))
1509               { startedge[last_number] = run->invers;
1510                 last_number++; MARK_V(vertex); }
1511                 tail++; *tail = run;
1512           }
1513           if (tail != limit)
1514             { tail++;
1515               *tail = temp = startedge[actual_number];  actual_number++; }
1516     }
1517 
1518     while (tail != limit)
1519                 /* Now we know that all numbers have been given */
1520     {
1521         for (run = temp->next; run != temp; run = run->next)
1522     /* this loop marks all edges around temp->origin. */
1523           { tail++; *tail = run; }
1524         if (tail != limit)
1525         {
1526        /* Next vertex to explore: */
1527             tail++;
1528             *tail = temp = startedge[actual_number];  actual_number++; }
1529     }
1530 }
1531 
1532 /****************************************************************************/
1533 
1534 static void
construct_numb_mirror(EDGE * givenedge,EDGE * numbering[])1535 construct_numb_mirror(EDGE *givenedge, EDGE *numbering[])
1536 
1537 /* Starts at givenedge and writes the edges in the well defined order
1538    into the list.  Works like testcanon. Look there for comments.  */
1539 {
1540     EDGE *temp, **tail, **limit, *run;
1541     EDGE *startedge[MAXN+1];
1542     int last_number, actual_number, vertex;
1543 
1544     RESETMARKS_V;
1545 
1546     tail = numbering; /* The first entry of the numbering list */
1547     limit = numbering+ne-1;  /* Last valid entry of the numbering list */
1548 
1549     MARK_V(givenedge->start);
1550     if (givenedge->start != givenedge->end)
1551       {
1552 	MARK_V(givenedge->end);
1553 	last_number = 2;
1554 	startedge[1] = givenedge->invers;
1555       }
1556     else last_number = 1;
1557 
1558     actual_number = 1;
1559     temp = *tail = givenedge;
1560 
1561     while (last_number < nv)
1562     {
1563         for (run = temp->prev; run != temp; run = run->prev)
1564     /* this loop marks all edges around temp->origin. */
1565           { vertex = run->end;
1566             if (!ISMARKED_V(vertex))
1567               { startedge[last_number] = run->invers;
1568                 last_number++; MARK_V(vertex); }
1569             tail++; *tail = run;
1570           }
1571           if (tail != limit)
1572             {
1573               tail++;
1574               *tail = temp = startedge[actual_number];  actual_number++; }
1575     }
1576 
1577     while (tail != limit)
1578                 /* Now we know that all numbers have been given */
1579     {
1580         for (run = temp->prev; run != temp; run = run->prev)
1581     /* this loop marks all edges around temp->origin. */
1582           { tail++; *tail = run; }
1583         if (tail != limit)
1584         {
1585        /* Next vertex to explore: */
1586             tail++;
1587             *tail = temp = startedge[actual_number];  actual_number++; }
1588     }
1589 }
1590 
1591 /****************************************************************************/
1592 
1593 static int
canon(int lcolour[],EDGE * can_numberings[][MAXE],int * nbtot,int * nbop)1594 canon(int lcolour[], EDGE *can_numberings[][MAXE], int *nbtot, int *nbop)
1595 
1596 /* Checks whether the last vertex (number: nv-1) is canonical or not.
1597    Returns 1 if yes, 0 if not. One of the criterions a canonical vertex
1598    must fulfill is that its colour is minimal.
1599 
1600    IT IS ASSUMED that the values of the colour function are positive
1601    and at most INT_MAX-MAXN.
1602 
1603    A possible starting edge for the construction of a representation is
1604    one with lexicographically minimal colour pair (start,INT_MAX-end).
1605    In can_numberings[][] the canonical numberings are stored as sequences
1606    of oriented edges.  For every 0 <= i,j < *nbtot and every
1607    0 <= k < ne the edges can_numberings[i][k] and can_numberings[j][k] can
1608    be mapped onto each other by an automorphism. The first
1609    *nbop numberings are orientation preserving while
1610    the rest is orientation reversing.
1611 
1612    In case of only 1 automorphism, in can_numberings[0][0] the "canonical"
1613    edge is given.  It is one edge emanating at the canonical vertex. The
1614    rest of the numbering is not given.
1615 
1616    In case of nontrivial automorphisms, can[0] starts with a list of edges
1617    adjacent to nv-1. In case of an orientation preserving numbering the deges
1618    are listed in ->next direction, otherwise in ->prev direction.
1619 
1620    Works OK if at least one vertex has valence >= 3. Otherwise some numberings
1621    are computed twice, since changing the orientation (the cyclic order around
1622    each vertex) doesn't change anything */
1623 {
1624     int i, last_vertex, test;
1625     int minstart, maxend; /* (minstart,maxend) will be the chosen colour
1626                                 pair of an edge */
1627     EDGE *startlist_last[5], *startlist[5*MAXN], *run, *end;
1628     int list_length_last, list_length;
1629     int representation[MAXE];
1630     EDGE *numblist[MAXE], *numblist_mirror[MAXE]; /* lists of edges where
1631                         starting gives a canonical representation */
1632     int numbs = 1, numbs_mirror = 0;
1633     int colour[MAXN];
1634 
1635     for (i=0; i<nv; i++) colour[i]=lcolour[i]+MAXN;
1636                                /* to distinguish colours from vertices */
1637     last_vertex = nv-1;
1638     minstart = colour[last_vertex];
1639 
1640 /* determine the smallest possible end for the vertex "last_vertex" */
1641 
1642     list_length_last = 1; startlist_last[0] = end = firstedge[last_vertex];
1643     maxend = colour[end->end];
1644 
1645     for (run = end->next; run != end; run = run->next)
1646       { if (colour[run->end] > maxend)
1647           { startlist_last[0] = run;
1648             list_length_last = 1; maxend = colour[run->end];}
1649         else if (colour[run->end] == maxend)
1650           { startlist_last[list_length_last] = run; list_length_last++; }
1651       }
1652 
1653 /* Now we know the pair that SHOULD be minimal and we can determine a list
1654    of all edges with this colour pair. If a new pair is found that is even
1655    smaller, we can return 0 at once */
1656 
1657     list_length = 0;
1658 
1659     for (i = 0; i < last_vertex; i++)
1660       { if (colour[i] < minstart) return 0;
1661         if (colour[i] == minstart)
1662           { run = end = firstedge[i];
1663             do
1664             {
1665               if (colour[run->end] > maxend) return 0;
1666               if (colour[run->end] == maxend)
1667                 { startlist[list_length] = run; list_length++; }
1668               run = run->next;
1669             } while (run != end);
1670           }
1671       }
1672 
1673 /* OK -- so there is no smaller pair and now we have to determine the
1674    smallest representation around vertex "last_vertex": */
1675 
1676     testcanon_first_init(startlist_last[0], representation, colour);
1677     numblist[0] = startlist_last[0];
1678     test = testcanon_mirror_init(startlist_last[0], representation, colour);
1679     if (test == 1)
1680       { numbs_mirror = 1; numblist_mirror[0] = startlist_last[0]; }
1681     else if (test == 2)
1682       { numbs_mirror = 1; numbs = 0;
1683         numblist_mirror[0] = startlist_last[0]; }
1684 
1685     for (i = 1; i < list_length_last; i++)
1686       { test = testcanon_init(startlist_last[i], representation, colour);
1687         if (test == 1) { numblist[numbs] = startlist_last[i]; numbs++; }
1688         else if (test == 2)
1689           { numbs_mirror = 0; numbs = 1; numblist[0] = startlist_last[i]; }
1690             test = testcanon_mirror_init(startlist_last[i],
1691                                                      representation, colour);
1692           if (test == 1)
1693             { numblist_mirror[numbs_mirror] = startlist_last[i];
1694               numbs_mirror++; }
1695           else if (test == 2)
1696             { numbs_mirror = 1; numbs = 0;
1697               numblist_mirror[0] = startlist_last[i]; }
1698       }
1699 
1700 /* Now we know the best representation we can obtain starting at last_vertex.
1701    Now we will check all the others. We can return 0 at once if we find a
1702    better one */
1703 
1704     for (i = 0; i < list_length; i++)
1705       { test = testcanon(startlist[i], representation, colour);
1706         if (test == 1) { numblist[numbs] = startlist[i]; numbs++; }
1707         else if (test == 2) return 0;
1708         test = testcanon_mirror(startlist[i], representation, colour);
1709         if (test == 1)
1710           { numblist_mirror[numbs_mirror] = startlist[i]; numbs_mirror++; }
1711         else if (test == 2) return 0;
1712       }
1713 
1714     *nbop = numbs;
1715     *nbtot = numbs+numbs_mirror;
1716 
1717     if (*nbtot>1)
1718       { for (i = 0; i < numbs; i++)
1719           construct_numb(numblist[i], can_numberings[i]);
1720         for (i = 0; i < numbs_mirror; i++, numbs++)
1721           construct_numb_mirror(numblist_mirror[i],can_numberings[numbs]);
1722       }
1723     else
1724       { if (numbs) can_numberings[0][0] = numblist[0];
1725         else can_numberings[0][0] = numblist_mirror[0]; }
1726 
1727     return 1;
1728 }
1729 
1730 /****************************************************************************/
1731 
1732 static int
canon_edge(EDGE * edgelist[],int num_edges,int lcolour[],EDGE * can_numberings[][MAXE],int * nbtot,int * nbop)1733 canon_edge(EDGE *edgelist[], int num_edges,
1734            int lcolour[], EDGE *can_numberings[][MAXE],
1735            int *nbtot, int *nbop)
1736 
1737 /*
1738    IT IS ASSUMED that the values of the colour function are positive and
1739    at most INT_MAX-MAXN.
1740 
1741    In case edgelist[0] == edgelist[1]->inverse, it checks whether
1742    edgelist[0] or edgelist[1] are canonical. Otherwise only
1743    edgelist[0] is checked to be canonical.
1744 
1745    It is only compared with the other edges contained in edgelist.
1746    The number of those edges in the list is given in num_edges.
1747    Returns 1 if yes, 0 if not.
1748 
1749    Edges given are not in minimal form -- but it is guaranteed that all
1750    colours of the startpoints are the same and all colours of the endpoints
1751    are the same.
1752 
1753    In case of only the identity automorphism, the entries of can_numberings[][]
1754    are undefined.
1755 
1756    Otherwise in can_numberings[][] the canonical numberings are stored as
1757    sequences of oriented edges.  For every 0 <= i,j < *nbtot
1758    and every 0 <= k < ne the edges can_numberings[i][k] and
1759    can_numberings[j][k] can be mapped onto each other by an automorphism.
1760    The first *nbop numberings are orientation
1761    preserving while the rest are orientation reversing.
1762 
1763    In case of an orientation preserving numbering the edges are listed in
1764    ->next direction, otherwise in ->prev direction.
1765 
1766    Works OK if at least one vertex has valence >= 3. Otherwise some numberings
1767    are computed twice, since changing the orientation (the cyclic order around
1768    each vertex) doesn't change anything */
1769 {
1770     int i, test;
1771     int representation[MAXE];
1772     EDGE *numblist[MAXE], *numblist_mirror[MAXE]; /* lists of edges where
1773                             starting gives a canonical representation */
1774     int numbs = 1, numbs_mirror = 0;
1775     int colour[MAXN];
1776 
1777     for (i=0; i<nv; i++) colour[i]=lcolour[i]+MAXN;
1778 				/* to distinguish colours from vertices */
1779 
1780 /* First we have to determine the smallest representation of edgelist[0] */
1781 
1782     testcanon_first_init(edgelist[0], representation, colour);
1783     numblist[0] = edgelist[0];
1784     test = testcanon_mirror_init(edgelist[0], representation, colour);
1785     if (test == 1)
1786       { numbs_mirror = 1; numblist_mirror[0] = edgelist[0]; }
1787     else if (test == 2)
1788       { numbs_mirror = 1; numbs = 0;
1789         numblist_mirror[0] = edgelist[0]; }
1790 
1791     if ((num_edges>1) && (edgelist[0]==edgelist[1]->invers))
1792       { test = testcanon_init(edgelist[1], representation, colour);
1793         if (test == 1) { numblist[numbs] = edgelist[1]; numbs++; }
1794         else if (test == 2)
1795           { numbs_mirror = 0; numbs = 1; numblist[0] = edgelist[1]; }
1796         test = testcanon_mirror_init(edgelist[1],representation, colour);
1797         if (test == 1)
1798           { numblist_mirror[numbs_mirror] = edgelist[1];
1799             numbs_mirror++; }
1800         else if (test == 2)
1801           { numbs_mirror = 1; numbs = 0;
1802             numblist_mirror[0] = edgelist[1]; }
1803         i=2; /* start rejecting at the second entry */
1804       }
1805     else i=1; /* start rejecting at the first entry */
1806 /* Now we know the best representation we can obtain with testedge.
1807    Next we will check all the others. We can return 0 at once if we find a
1808    better one */
1809 
1810     for ( ; i < num_edges; i++)
1811       { test = testcanon(edgelist[i], representation, colour);
1812         if (test == 1) { numblist[numbs] = edgelist[i]; numbs++; }
1813         else if (test == 2) return 0;
1814         test = testcanon_mirror(edgelist[i], representation, colour);
1815         if (test == 1)
1816           { numblist_mirror[numbs_mirror] = edgelist[i]; numbs_mirror++; }
1817         else if (test == 2) return 0;
1818       }
1819 
1820     *nbop = numbs;
1821     *nbtot = numbs+numbs_mirror;
1822 
1823     if (*nbtot > 1)
1824       {
1825         for (i = 0; i < numbs; i++)
1826             construct_numb(numblist[i], can_numberings[i]);
1827         for (i = 0; i < numbs_mirror; i++, numbs++)
1828             construct_numb_mirror(numblist_mirror[i],can_numberings[numbs]);
1829       }
1830 
1831     return 1;
1832 }
1833 
1834 /****************************************************************************/
1835 
1836 static int
canon_edge_oriented(EDGE * edgelist_or[],int num_edges_or,int can_edges_or,EDGE * edgelist_inv[],int num_edges_inv,int can_edges_inv,int lcolour[],EDGE * can_numberings[][MAXE],int * nbtot,int * nbop)1837 canon_edge_oriented(EDGE *edgelist_or[], int num_edges_or, int can_edges_or,
1838 		    EDGE *edgelist_inv[], int num_edges_inv, int can_edges_inv,
1839 		    int lcolour[], EDGE *can_numberings[][MAXE],
1840 		    int *nbtot, int *nbop)
1841 
1842 /*
1843    IT IS ASSUMED that the values of the colour function are positive
1844    and at most INT_MAX-MAXN.
1845 
1846    This routine checks all num_edges_or elements of edgelist_or just for one
1847    orientation and all num_edges_inv elements of the list edgelist_inv just
1848    for the other. It returns 1 if and only if one of the first can_edges_or
1849    elements of the first list or first can_edges_inv elements of the second
1850    give an optimal numbering among all the possibilities provided by the
1851    lists.
1852 
1853    Edges given are not in minimal form -- but it is guaranteed that all
1854    colours of the startpoints are the same and all colours of the endpoints
1855    are the same.
1856 
1857    In case of only the identity automorphism, the entries of can_numberings[][]
1858    are undefined.
1859 
1860    Otherwise in can_numberings[][] the canonical numberings are stored as
1861    sequences of oriented edges.  For every 0 <= i,j < *nbtot
1862    and every 0 <= k < ne the edges can_numberings[i][k] and
1863    can_numberings[j][k] can be mapped onto each other by an automorphism.
1864    The first *nbop numberings are orientation
1865    preserving while the rest are orientation reversing.
1866 
1867    In case of an orientation preserving numbering the edges are listed in
1868    ->next direction, otherwise in ->prev direction.
1869 
1870    Works OK if at least one vertex has valence >= 3. Otherwise some numberings
1871    are computed twice, since changing the orientation (the cyclic order around
1872    each vertex) doesn't change anything */
1873 {
1874     int i, test;
1875     int representation[MAXE];
1876     EDGE *numblist[MAXE], *numblist_mirror[MAXE]; /* lists of edges where
1877                             starting gives a canonical representation */
1878     int numbs = 1, numbs_mirror = 0;
1879     int colour[MAXN];
1880 
1881     for (i=0; i<nv; i++) colour[i]=lcolour[i]+MAXN;
1882 			     /* to distinguish colours from vertices */
1883 
1884 /* First we have to determine the smallest representation possible with
1885    edgelist_or */
1886 
1887     if (can_edges_or > 0)
1888       { testcanon_first_init(edgelist_or[0], representation, colour);
1889 	numblist[0] = edgelist_or[0];
1890 	for (i=1; i<can_edges_or; i++)
1891 	  { test = testcanon_init(edgelist_or[i], representation, colour);
1892 	    if (test == 1) { numblist[numbs] = edgelist_or[i]; numbs++; }
1893 	    else if (test == 2)
1894 	      { numbs = 1; numblist[0] = edgelist_or[i]; }
1895 	  }
1896 	i=0; /* the next for-loop can start at the beginning */
1897       }
1898     else
1899       { numbs=0; numbs_mirror=1;
1900         testcanon_first_init_mirror(edgelist_inv[0], representation, colour);
1901         numblist_mirror[0] = edgelist_inv[0];
1902 	i=1; /* the next for-loop must start at position 1 */
1903       }
1904 
1905     for (   ; i<can_edges_inv; i++)
1906       { test = testcanon_mirror_init(edgelist_inv[i], representation, colour);
1907         if (test == 1)
1908           { numblist_mirror[numbs_mirror] = edgelist_inv[i]; numbs_mirror++; }
1909 	else if (test == 2)
1910 	  { numbs = 0; numbs_mirror=1; numblist_mirror[0] = edgelist_inv[i]; }
1911       }
1912 
1913 
1914     /* now we know the best we can get for a "canonical edge".
1915        Next we will check all the others. We can return 0 at once if we find a
1916        better one */
1917 
1918     for (i=can_edges_or ; i < num_edges_or; i++)
1919       { test = testcanon(edgelist_or[i], representation, colour);
1920         if (test == 1) { numblist[numbs] = edgelist_or[i]; numbs++; }
1921         else if (test == 2) return 0;
1922       }
1923     for (i=can_edges_inv ; i < num_edges_inv; i++)
1924       { test = testcanon_mirror(edgelist_inv[i], representation, colour);
1925         if (test == 1)
1926           { numblist_mirror[numbs_mirror] = edgelist_inv[i]; numbs_mirror++; }
1927         else if (test == 2) return 0;
1928       }
1929 
1930     *nbop = numbs;
1931     *nbtot = numbs+numbs_mirror;
1932 
1933     if (*nbtot > 1)
1934       {
1935         for (i = 0; i < numbs; i++)
1936             construct_numb(numblist[i], can_numberings[i]);
1937         for (i = 0; i < numbs_mirror; i++, numbs++)
1938             construct_numb_mirror(numblist_mirror[i],can_numberings[numbs]);
1939       }
1940 
1941     return 1;
1942 }
1943 
1944 /**************************************************************************/
1945 
1946 static int
non_facial_triangles(void)1947 non_facial_triangles(void)
1948 
1949 /* Count the non_facial triangles.
1950    Algorithm: we look for such triangles a-b-c-a, where a<b<c.
1951    For each b, mark the neighbours a < b.  Then, for each neighbour
1952    c > b, count the marked neighbours not consecutive to b.
1953 */
1954 {
1955     int b,nt;
1956     EDGE *e,*elast,*ec,*eclast;
1957 
1958     nt = 0;
1959     for (b = 1; b < nv-1; ++b)
1960     {
1961         RESETMARKS_V;
1962         e = elast = firstedge[b];
1963         do
1964         {
1965             if (e->end < b) MARK_V(e->end);
1966             e = e->next;
1967         } while (e != elast);
1968         do
1969         {
1970             if (e->end > b && degree[e->end] >= 4)
1971             {
1972                 eclast = e->invers;
1973                 ec = eclast->next->next;
1974                 eclast = eclast->prev;
1975                 for (; ec != eclast; ec = ec->next) if (ISMARKED_V(ec->end)) ++nt;
1976             }
1977             e = e->next;
1978         } while (e != elast);
1979     }
1980 
1981     return nt;
1982 }
1983 
1984 /**************************************************************************/
1985 
1986 static int
has_non_facial_triangle(void)1987 has_non_facial_triangle(void)
1988 
1989 /* Test if there is a non-facial-triangle in a triangulation.
1990    Algorithm: we look for such triangles a-b-c-a, where a<b<c.
1991    For each b, mark the neighbours a < b.  Then, for each neighbour
1992    c > b, count the marked neighbours not consecutive to b.
1993 */
1994 {
1995     int b;
1996     EDGE *e,*elast,*ec,*eclast;
1997 
1998     for (b = 1; b < nv-1; ++b)
1999     {
2000         RESETMARKS_V;
2001         e = elast = firstedge[b];
2002         do
2003         {
2004             if (e->end < b) MARK_V(e->end);
2005             e = e->next;
2006         } while (e != elast);
2007         do
2008         {
2009             if (e->end > b && degree[e->end] >= 4)
2010             {
2011                 eclast = e->invers;
2012                 ec = eclast->next->next;
2013                 eclast = eclast->prev;
2014                 for (; ec != eclast; ec = ec->next)
2015 		    if (ISMARKED_V(ec->end)) return TRUE;
2016             }
2017             e = e->next;
2018         } while (e != elast);
2019     }
2020 
2021     return FALSE;
2022 }
2023 
2024 /****************************************************************************/
2025 
2026 static int
numbermarked(void)2027 numbermarked(void)
2028 {
2029   int list[MAXN], i, index, number, dummy, top, buffer;
2030   EDGE *run;
2031 
2032   for (top=0;(top<nv) && ISMARKED_V(top);top++);
2033   if (top==nv) {fprintf(stderr,"SHIT\n"); exit(1); }
2034 
2035   MARK_V(top);
2036   list[0]=top;
2037   number=1;
2038   index=0;
2039 
2040   while (index<number)
2041     { dummy=list[index];
2042     run=firstedge[dummy];
2043     for (i=0;i<degree[dummy];i++, run=run->next)
2044       { buffer=run->end;
2045       if (!ISMARKED_V(buffer))
2046       { MARK_V(buffer); list[number]=buffer; number++; }
2047       }
2048     index++;
2049     }
2050   return number;
2051 }
2052 
2053 static int
hastwocut(void)2054 hastwocut(void)
2055 {
2056   int i,j;
2057 
2058   for (i=0;i<nv-1;i++)
2059     for (j=i+1;j<nv;j++)
2060       { RESETMARKS_V;
2061       MARK_V(i); MARK_V(j);
2062       if (numbermarked()<(nv-2)) return 1;
2063       }
2064   return 0;
2065 }
2066 
2067 static int
hascutvertex(void)2068 hascutvertex(void)
2069 {int i;
2070 
2071  if (nv>2) { for (i=0;i<nv;i++) if (degree[i]==1) return 1; }
2072 
2073  for (i=0;i<nv;i++)
2074    {RESETMARKS_V;
2075    MARK_V(i);
2076    if (numbermarked()<(nv-1)) return 1; }
2077 
2078    return 0;
2079 }
2080 
2081 static int
connectivity(void)2082 connectivity(void)
2083 /* Connectivity - very slow, testing only.
2084    Returns 3 for connectivity >= 3. */
2085 {
2086 
2087   if (hascutvertex()) return 1;
2088   if (hastwocut()) return 2;
2089   return 3;
2090 }
2091 
2092 /****************************************************************************/
2093 
2094 static int
numedgeorbits(int nbtot,int nbop)2095 numedgeorbits(int nbtot, int nbop)
2096 
2097 /* return number of orbits of directed edges, under the
2098    orientation-preserving automorphism group (assumed computed) */
2099 {
2100     register EDGE **nb0,**nblim,**nb;
2101     register int i,j;
2102 
2103     if (nbtot == 1)
2104         return ne;
2105     else
2106     {
2107         nb0 = (EDGE**) numbering[0];
2108         if (nbop == 0) nblim = (EDGE**) numbering[nbtot];
2109         else           nblim = (EDGE**) numbering[nbop];
2110 
2111         RESETMARKS;
2112 
2113         j = 0;
2114         for (i = 0; i < ne; ++i, ++nb0)
2115             if (!ISMARKEDLO(*nb0))
2116             {
2117                 ++j;
2118                 for (nb = nb0; nb < nblim; nb += MAXE) MARKLO(*nb);
2119             }
2120         return j;
2121     }
2122 }
2123 
2124 /****************************************************************************/
2125 
2126 static int
numfaceorbits(int nbtot,int nbop)2127 numfaceorbits(int nbtot, int nbop)
2128 
2129 /* return number of orbits of faces, under the full group
2130    (assumed computed).  This is supposed to work even if the
2131    graph is only 1-connected. */
2132 {
2133     EDGE **nb0,**nblim,**nb,**nboplim;
2134     EDGE *e,*elast,*ee;
2135     int i,count;
2136 
2137     RESETMARKS;
2138     count = 0;
2139 
2140     if (nbtot == 1)
2141     {
2142         for (i = 0; i < nv; ++i)
2143         {
2144             e = elast = firstedge[i];
2145             do
2146             {
2147                 if (!ISMARKEDLO(e))
2148                 {
2149                     ++count;
2150                     ee = e;
2151                     do
2152                     {
2153                         MARKLO(ee);
2154                         ee = ee->invers->prev;
2155                     } while (ee != e);
2156                 }
2157                 e = e->next;
2158             } while (e != elast);
2159         }
2160     }
2161     else
2162     {
2163         nb0 = (EDGE**) numbering[0];
2164         nblim = (EDGE**) numbering[nbtot];
2165         nboplim = (EDGE**)numbering[nbop==0?nbtot:nbop];
2166 
2167         for (i = 0; i < ne; ++i) nb0[i]->index = i;
2168 
2169         for (i = 0; i < nv; ++i)
2170         {
2171 	    e = elast = firstedge[i];
2172 	    do
2173 	    {
2174                 if (!ISMARKEDLO(e))
2175                 {
2176                     ++count;
2177 		    ee = e;
2178 		    do
2179 		    {
2180                         for (nb = nb0+ee->index; nb < nboplim; nb += MAXE)
2181                             MARKLO(*nb);
2182                         for ( ; nb < nblim; nb += MAXE)
2183                             MARKLO((*nb)->invers);
2184 		        ee = ee->invers->prev;
2185 		    } while (ee != e);
2186                 }
2187 	        e = e->next;
2188 	    } while (e != elast);
2189         }
2190     }
2191 
2192     return count;
2193 }
2194 
2195 /****************************************************************************/
2196 
2197 static int
numopfaceorbits(int nbtot,int nbop)2198 numopfaceorbits(int nbtot, int nbop)
2199 
2200 /* return number of orbits of faces, under the orientation-preserving
2201    group (assumed computed).  This is supposed to work even if the
2202    graph is only 1-connected. */
2203 {
2204     EDGE **nb0,**nb,**nboplim;
2205     EDGE *e,*elast,*ee;
2206     int i,count;
2207 
2208     RESETMARKS;
2209     count = 0;
2210 
2211     if (nbtot == 1)
2212     {
2213         for (i = 0; i < nv; ++i)
2214         {
2215             e = elast = firstedge[i];
2216             do
2217             {
2218                 if (!ISMARKEDLO(e))
2219                 {
2220                     ++count;
2221                     ee = e;
2222                     do
2223                     {
2224                         MARKLO(ee);
2225                         ee = ee->invers->prev;
2226                     } while (ee != e);
2227                 }
2228                 e = e->next;
2229             } while (e != elast);
2230         }
2231     }
2232     else
2233     {
2234         nb0 = (EDGE**) numbering[0];
2235         nboplim = (EDGE**)numbering[nbop==0?nbtot:nbop];
2236 
2237         for (i = 0; i < ne; ++i) nb0[i]->index = i;
2238 
2239         for (i = 0; i < nv; ++i)
2240         {
2241 	    e = elast = firstedge[i];
2242 	    do
2243 	    {
2244                 if (!ISMARKEDLO(e))
2245                 {
2246                     ++count;
2247 		    ee = e;
2248 		    do
2249 		    {
2250                         for (nb = nb0+ee->index; nb < nboplim; nb += MAXE)
2251                             MARKLO(*nb);
2252 		        ee = ee->invers->prev;
2253 		    } while (ee != e);
2254                 }
2255 	        e = e->next;
2256 	    } while (e != elast);
2257         }
2258     }
2259 
2260     return count;
2261 }
2262 
2263 /****************************************************************************/
2264 
2265 static int
numorbits(int nbtot,int nbop)2266 numorbits(int nbtot, int nbop)
2267 
2268 /* return number of orbits of vertices, under the full group
2269    (assumed computed). */
2270 
2271 {
2272     EDGE **nb0,**nblim,**nb;
2273     int vindex[MAXN];
2274     int i,count;
2275 
2276     if (nbtot == 1) return nv;
2277 
2278     nb0 = (EDGE**) numbering[0];
2279     nblim = (EDGE**) numbering[nbtot];
2280 
2281     for (i = 0; i < ne; ++i) vindex[nb0[i]->start] = i;
2282 
2283     RESETMARKS_V;
2284 
2285     count = 0;
2286     for (i = 0; i < nv; ++i)
2287         if (!ISMARKED_V(i))
2288         {
2289             ++count;
2290             for (nb = nb0+vindex[i]; nb < nblim; nb += MAXE)
2291                 MARK_V((*nb)->start);
2292         }
2293 
2294     return count;
2295 }
2296 
2297 /****************************************************************************/
2298 
2299 static int
numoporbits(int nbtot,int nbop)2300 numoporbits(int nbtot, int nbop)
2301 
2302 /* return number of orbits of vertices, under the orientation-preserving
2303    group (assumed computed). */
2304 
2305 {
2306     EDGE **nb0,**nb,**nboplim;
2307     int vindex[MAXN];
2308     int i,count;
2309 
2310     if (nbtot == 1) return nv;
2311 
2312     nb0 = (EDGE**) numbering[0];
2313     nboplim = (EDGE**)numbering[nbop==0?nbtot:nbop];
2314 
2315     for (i = 0; i < ne; ++i) vindex[nb0[i]->start] = i;
2316 
2317     RESETMARKS_V;
2318 
2319     count = 0;
2320     for (i = 0; i < nv; ++i)
2321         if (!ISMARKED_V(i))
2322         {
2323             ++count;
2324             for (nb = nb0+vindex[i]; nb < nboplim; nb += MAXE)
2325                 MARK_V((*nb)->start);
2326         }
2327 
2328     return count;
2329 }
2330 
2331 /****************************************************************************/
2332 
2333 static int
numorbitsonface(int nbtot,int nbop,EDGE * e)2334 numorbitsonface(int nbtot, int nbop, EDGE *e)
2335 
2336 /* return number of orbits of directed edges in the face to
2337    the left of edge e, under the orientation-preserving
2338    automorphism group (assumed computed) */
2339 {
2340     register EDGE **nb0,**nblim,**nb;
2341     register EDGE *e1;
2342     register int i,j;
2343 
2344     RESETMARKS;
2345 
2346     j = 0;
2347     e1 = e;
2348     do
2349     {
2350 	MARKLO(e1);
2351 	++j;
2352 	e1 = e1->invers->next;
2353     } while (e1 != e);
2354 
2355     if (nbtot == 1)
2356         return j;
2357     else
2358     {
2359         nb0 = (EDGE**) numbering[0];
2360         if (nbop == 0) nblim = (EDGE**) numbering[nbtot];
2361         else           nblim = (EDGE**) numbering[nbop];
2362 
2363         j = 0;
2364         for (i = 0; i < ne; ++i, ++nb0)
2365             if (ISMARKEDLO(*nb0))
2366             {
2367                 ++j;
2368                 for (nb = nb0; nb < nblim; nb += MAXE) UNMARK(*nb);
2369             }
2370         return j;
2371     }
2372 }
2373 
2374 /**************************************************************************/
2375 
2376 static void
make_octahedron(void)2377 make_octahedron(void)
2378 
2379 /* Make an octahedron using the first 24 edges */
2380 {
2381    int i;
2382    EDGE *buffer;
2383 
2384     for (i=0; i<=5; i++)
2385       { buffer=edges+4*i;
2386         firstedge[i]=buffer; degree[i]=4;
2387         buffer->next=buffer+1; buffer->prev=buffer+3; buffer->start=i;
2388         buffer++; buffer->next=buffer+1; buffer->prev=buffer-1; buffer->start=i;
2389         buffer++; buffer->next=buffer+1; buffer->prev=buffer-1; buffer->start=i;
2390         buffer++; buffer->next=buffer-3; buffer->prev=buffer-1; buffer->start=i;
2391       }
2392 
2393     buffer=edges; /* edge number 0 */
2394     buffer->end=4;
2395     buffer->invers=edges+16;
2396     buffer->min=buffer;
2397 
2398     buffer++; /* edge number 1 */
2399     buffer->end=1;
2400     buffer->invers=edges+4;
2401     buffer->min=buffer;
2402 
2403     buffer++; /* edge number 2 */
2404     buffer->end=2;
2405     buffer->invers=edges+8;
2406     buffer->min=buffer;
2407 
2408     buffer++; /* edge number 3 */
2409     buffer->end=3;
2410     buffer->invers=edges+12;
2411     buffer->min=buffer;
2412 
2413     buffer++; /* edge number 4 */
2414     buffer->end=0;
2415     buffer->invers=edges+1;
2416     buffer->min=buffer->invers;
2417 
2418     buffer++; /* edge number 5 */
2419     buffer->end=4;
2420     buffer->invers=edges+19;
2421     buffer->min=buffer;
2422 
2423     buffer++; /* edge number 6 */
2424     buffer->end=5;
2425     buffer->invers=edges+20;
2426     buffer->min=buffer;
2427 
2428     buffer++; /* edge number 7 */
2429     buffer->end=2;
2430     buffer->invers=edges+9;
2431     buffer->min=buffer;
2432 
2433     buffer++; /* edge number 8 */
2434     buffer->end=0;
2435     buffer->invers=edges+2;
2436     buffer->min=buffer->invers;
2437 
2438     buffer++; /* edge number 9 */
2439     buffer->end=1;
2440     buffer->invers=edges+7;
2441     buffer->min=buffer->invers;
2442 
2443     buffer++; /* edge number 10 */
2444     buffer->end=5;
2445     buffer->invers=edges+23;
2446     buffer->min=buffer;
2447 
2448     buffer++; /* edge number 11 */
2449     buffer->end=3;
2450     buffer->invers=edges+13;
2451     buffer->min=buffer;
2452 
2453     buffer++; /* edge number 12 */
2454     buffer->end=0;
2455     buffer->invers=edges+3;
2456     buffer->min=buffer->invers;
2457 
2458     buffer++; /* edge number 13 */
2459     buffer->end=2;
2460     buffer->invers=edges+11;
2461     buffer->min=buffer->invers;
2462 
2463     buffer++; /* edge number 14 */
2464     buffer->end=5;
2465     buffer->invers=edges+22;
2466     buffer->min=buffer;
2467 
2468     buffer++; /* edge number 15 */
2469     buffer->end=4;
2470     buffer->invers=edges+17;
2471     buffer->min=buffer;
2472 
2473     buffer++; /* edge number 16 */
2474     buffer->end=0;
2475     buffer->invers=edges;
2476     buffer->min=buffer->invers;
2477 
2478     buffer++; /* edge number 17 */
2479     buffer->end=3;
2480     buffer->invers=edges+15;
2481     buffer->min=buffer->invers;
2482 
2483     buffer++; /* edge number 18 */
2484     buffer->end=5;
2485     buffer->invers=edges+21;
2486     buffer->min=buffer;
2487 
2488     buffer++; /* edge number 19  */
2489     buffer->end=1;
2490     buffer->invers=edges+5;
2491     buffer->min=buffer->invers;
2492 
2493     buffer++; /* edge number 20 */
2494     buffer->end=1;
2495     buffer->invers=edges+6;
2496     buffer->min=buffer->invers;
2497 
2498     buffer++; /* edge number 21 */
2499     buffer->end=4;
2500     buffer->invers=edges+18;
2501     buffer->min=buffer->invers;
2502 
2503     buffer++; /* edge number 22 */
2504     buffer->end=3;
2505     buffer->invers=edges+14;
2506     buffer->min=buffer->invers;
2507 
2508     buffer++; /* edge number 23 */
2509     buffer->end=2;
2510     buffer->invers=edges+10;
2511     buffer->min=buffer->invers;
2512 
2513     nv=6;
2514     ne=24;
2515 }
2516 
2517 /**************************************************************************/
2518 
2519 static void
initialize_bip(void)2520 initialize_bip(void)
2521 
2522 /* initialize edges for bipartite generation, and make the
2523    inital octahedron */
2524 {
2525     EDGE *run,*start;
2526     int n;
2527 
2528 /* First initialize the edges for the P-operation. They look like
2529 
2530        a
2531       / \
2532   ---b---c   Vertex c is the point where the reference edge is glued to.
2533       \ /      c--->b is the first edge P_op(n)
2534        d
2535 
2536 a and d will be from the old graph -- they cannot be initialised so far.
2537 It is assumed that for 0<=n<MAXN after P_op(n) there is room for 12 edges.
2538 */
2539 
2540     for (n=6; n<=MAXN-2; n++)
2541       { run=start=P_op(n);
2542         run->start=n; run->end=n+1; run->min=run;
2543             run->invers=start+1; run->next=start+2; run->prev=start+4;
2544         run=start+1; run->start=n+1; run->end=n;
2545             run->min=run->invers=start; run->next=start+7; run->prev=start+11;
2546         run=start+2; run->start=n; run->min=run; run->invers=start+3;
2547             run->prev=start;
2548         run=start+3; run->end=n; run->min=run->invers=start+2;
2549             run->next=start+10;
2550         run=start+4; run->start=n; run->min=run; run->invers=start+5;
2551             run->next=start;
2552         run=start+5; run->end=n; run->min=run->invers=start+4;
2553             run->prev=start+6;
2554         run=start+6; run->end=n+1; run->min=run; run->invers=start+7;
2555             run->next=start+5;
2556         run=start+7; run->start=n+1; run->min=run->invers=start+6;
2557             run->next=start+9; run->prev=start+1;
2558         run=start+8; run->end=n+1; run->min=run; run->invers=start+9;
2559         run=start+9; run->start=n+1; run->min=run->invers=start+8;
2560             run->next=start+11; run->prev=start+7;
2561         run=start+10; run->end=n+1; run->min=run; run->invers=start+11;
2562             run->prev=start+3;
2563         run=start+11; run->start=n+1; run->min=run->invers=start+10;
2564             run->next=start+1; run->prev=start+9;
2565       }
2566 
2567 /* The new edges for the Q-operations look like
2568 
2569    |\
2570    | \ c  Vertex c is the point where the reference edge is glued to
2571    | /    and the only new vertex
2572    |/
2573 
2574 */
2575 
2576    for (n=6; n<=MAXN-1; n++)
2577      { run=start=Q_op(n);  run->min=run;
2578                    run->start=n; run->invers=start+1; run->next=start+4;
2579        run=start+1; run->end=n; run->invers=run->min=start;
2580 	   run->prev=start+2;
2581        run=start+2; run->invers=start+3; run->next=start+1; run->min=run;
2582        run=start+3; run->invers=run->min=start+2; run->prev=start+5;
2583        run=start+4; run->start=n; run->invers=start+5; run->prev=start;
2584 	   run->min=run;
2585        run=start+5; run->end=n; run->invers=run->min=start+4;
2586            run->next=start+3;
2587      }
2588 
2589    make_octahedron();
2590 }
2591 
2592 /**************************************************************************/
2593 
2594 static void
initialize_min4(void)2595 initialize_min4(void)
2596 
2597 /* initialize edges for mindegree=4 generation, and make the
2598    inital octahedron */
2599 {
2600     EDGE *run,*start;
2601     int i,n;
2602 
2603 /* First initialise the edges for the four-operation. */
2604 
2605     for (n=6; n<=MAXN; n++)
2606       { start=four_op(n);
2607         for (i=0, run=start; i<6; i+=2)
2608           { run->start=n; run->min=run; run->invers=run+1; run++;
2609             run->end=n; run->invers=run->min=run-1; run++; }
2610         run=start; run->next=run+2;
2611         run+=2; /*2*/ run->prev=start; run->next=run+2;
2612         run+=2; /*4*/ run->prev=start+2;
2613       }
2614 
2615 /* Then initialise the edges for the five-operation. */
2616 
2617     for (n=6; n<=MAXN; n++)
2618       { start=five_op(n);
2619         for (i=0, run=start; i<6; i+=2)
2620           { run->start=n; run->min=run; run->invers=run+1; run++;
2621             run->end=n; run->invers=run->min=run-1; run++; }
2622         run=start; run->next=run+2;
2623         run+=2; /*2*/ run->prev=start;
2624       }
2625 
2626 /* Then initialise the edges for the S-operation. */
2627 
2628     for (n=6; n<=MAXN-3; n++)
2629       { start=S_op(n);
2630         for (i=0;i<18;i+=2)
2631           { run=start+i; run->invers=run+1; run->min=run;
2632             run++; run->invers=run->min=run-1; }
2633 
2634         run=start;    run->start=n+1; run->end=n; run->next=start+4;
2635                       run->prev=start+9;
2636         run++; /*1*/  run->start=n; run->end=n+1; run->next=start+11;
2637                       run->prev=start+3;
2638         run++; /*2*/  run->start=n+2; run->end=n; run->next=start+15;
2639                       run->prev=start+5;
2640         run++; /*3*/  run->start=n; run->end=n+2; run->next=start+1;
2641                       run->prev=start+13;
2642         run++; /*4*/  run->start=n+1; run->end=n+2; run->next=start+7;
2643                       run->prev=start;
2644         run++; /*5*/  run->start=n+2; run->end=n+1; run->next=start+2;
2645                       run->prev=start+17;
2646         run++; /*6*/  run->end=n+1; run->next=start+16;
2647         run++; /*7*/  run->start=n+1; run->next=start+9; run->prev=start+4;
2648         run++; /*8*/  run->end=n+1; run->prev=start+10;
2649         run++; /*9*/  run->start=n+1; run->next=start; run->prev=start+7;
2650         run++; /*10*/ run->end=n; run->next=start+8;
2651         run++; /*11*/ run->start=n;  run->next=start+13; run->prev=start+1;
2652         run++; /*12*/ run->end=n; run->prev=start+14;
2653         run++; /*13*/ run->start=n; run->next=start+3; run->prev=start+11;
2654         run++; /*14*/ run->end=n+2; run->next=start+12;
2655         run++; /*15*/ run->start=n+2; run->next=start+17; run->prev=start+2;
2656         run++; /*16*/ run->end=n+2; run->prev=start+6;
2657         run++; /*17*/ run->start=n+2; run->next=start+5; run->prev=start+15;
2658       }
2659 
2660     make_octahedron();
2661 }
2662 
2663 /**************************************************************************/
2664 
2665 static void
initialize_triang(void)2666 initialize_triang(void)
2667 
2668 /* initialize stars and create initial K4, for ordinary triangulations */
2669 {
2670     register int i,j;
2671     register EDGE *si;
2672 
2673     for (i = 0; i < MAXN; ++i)
2674     {
2675         si = STAR3(i);
2676 
2677         for (j = 0; j < 3; ++j)
2678         {
2679             si[j].end = si[j+3].start = i;
2680             si[j].invers = si + 3 + j;
2681             si[j+3].invers = si + j;
2682             si[j].min = si[j+3].min = si + j;
2683             si[j+3].next = si + 3 + (j+1) % 3;
2684             si[j+3].prev = si + 3 + (j+2) % 3;
2685         }
2686 
2687         si = STAR4(i);
2688 
2689         for (j = 0; j < 4; ++j)
2690         {
2691             si[j].end = si[j+4].start = i;
2692             si[j].invers = si + 4 + j;
2693             si[j+4].invers = si + j;
2694             si[j].min = si[j+4].min = si + j;
2695             si[j+4].next = si + 4 + (j+1) % 4;
2696             si[j+4].prev = si + 4 + (j+3) % 4;
2697         }
2698 
2699         si = STAR5(i);
2700 
2701         for (j = 0; j < 5; ++j)
2702         {
2703             si[j].end = si[j+5].start = i;
2704             si[j].invers = si + 5 + j;
2705             si[j+5].invers = si + j;
2706             si[j].min = si[j+5].min = si + j;
2707             si[j+5].next = si + 5 + (j+1) % 5;
2708             si[j+5].prev = si + 5 + (j+4) % 5;
2709         }
2710     }
2711 
2712     init_edge[0].start = 0; init_edge[0].end = 1;
2713     init_edge[0].next = init_edge[0].prev = init_edge+2;
2714     init_edge[0].invers = init_edge+1;
2715     init_edge[0].min = init_edge;
2716 
2717     init_edge[1].start = 1; init_edge[1].end = 0;
2718     init_edge[1].next = init_edge[1].prev = init_edge+4;
2719     init_edge[1].invers = init_edge+0;
2720     init_edge[1].min = init_edge;
2721 
2722     init_edge[2].start = 0; init_edge[2].end = 2;
2723     init_edge[2].next = init_edge[2].prev = init_edge+0;
2724     init_edge[2].invers = init_edge+3;
2725     init_edge[2].min = init_edge+2;
2726 
2727     init_edge[3].start = 2; init_edge[3].end = 0;
2728     init_edge[3].next = init_edge[3].prev = init_edge+5;
2729     init_edge[3].invers = init_edge+2;
2730     init_edge[3].min = init_edge+2;
2731 
2732     init_edge[4].start = 1; init_edge[4].end = 2;
2733     init_edge[4].next = init_edge[4].prev = init_edge+1;
2734     init_edge[4].invers = init_edge+5;
2735     init_edge[4].min = init_edge+4;
2736 
2737     init_edge[5].start = 2; init_edge[5].end = 1;
2738     init_edge[5].next = init_edge[5].prev = init_edge+3;
2739     init_edge[5].invers = init_edge+4;
2740     init_edge[5].min = init_edge+4;
2741 
2742     nv = 3;
2743     ne = 6;
2744 
2745     degree[0] = degree[1] = degree[2] = 2;
2746     firstedge[0] = init_edge;
2747     firstedge[1] = init_edge+1;
2748     firstedge[2] = init_edge+3;
2749 
2750     extend3(init_edge);
2751 }
2752 
2753 /**************************************************************************/
2754 
2755 static void
find_extensions(int numb_total,int numb_pres,EDGE * ext3[],int * numext3,EDGE * ext4[],int * numext4,EDGE * ext5[],int * numext5)2756 find_extensions(int numb_total, int numb_pres,
2757                 EDGE *ext3[], int *numext3,
2758                 EDGE *ext4[], int *numext4,
2759                 EDGE *ext5[], int *numext5)
2760 
2761 /* Find all nonequivalent places for extension.
2762    These are listed in ext# according to the degree of the future new vertex.
2763    The number of cases is returned in next# (#=3,4,5). */
2764 {
2765     register int i,k;
2766     int deg3,deg4;
2767     register EDGE *e,*e1,*e2,*ex;
2768     EDGE **nb0,**nb1,**nbop,**nblim;
2769 
2770     deg3 = deg4 = 0;
2771     for (i = 0; i < nv; ++i)
2772         if      (degree[i] == 3) ++deg3;
2773         else if (degree[i] == 4) ++deg4;
2774 
2775      /* code for trivial group */
2776 
2777     if (numb_total == 1)
2778     {
2779         k = 0;
2780         for (i = 0; i < nv; ++i)
2781         {
2782             e = ex = firstedge[i];
2783             do
2784             {
2785                 e1 = e->invers->prev;
2786                 if (e1 > e)
2787                 {
2788                     e1 = e1->invers->prev;
2789                     if (e1 > e) ext3[k++] = e;
2790                 }
2791                 e = e->next;
2792             } while (e != ex);
2793         }
2794         *numext3 = k;
2795 
2796         if (deg3 <= 2 && !Aswitch)
2797         {
2798             k = 0;
2799             for (i = 0; i < nv; ++i)
2800             {
2801                 if (degree[i] == 3) continue;
2802                 e = ex = firstedge[i];
2803                 do
2804                 {
2805                     e1 = e->next;
2806                     if (e1->invers > e1)
2807                     {
2808                         e2 = e1->invers->prev;
2809                         if ((degree[e->end] == 3)
2810                                 + (degree[e2->end] == 3) == deg3)
2811                             ext4[k++] = e;
2812                     }
2813                     e = e->next;
2814                 } while (e != ex);
2815             }
2816             *numext4 = k;
2817         }
2818         else
2819             *numext4 = 0;
2820 
2821         if (deg3 == 0 && deg4 <= 2 && !Aswitch)
2822         {
2823             k = 0;
2824             for (i = 0; i < nv; ++i)
2825             {
2826                 if (degree[i] < 6) continue;
2827                 e = ex = firstedge[i];
2828                 do
2829                 {
2830                     e1 = e->next->next->next;
2831                     if ((degree[e->end] == 4)
2832                              + (degree[e1->end] == 4) == deg4)
2833                         ext5[k++] = e;
2834                     e = e->next;
2835                 } while (e != ex);
2836             }
2837             *numext5 = k;
2838         }
2839         else
2840             *numext5 = 0;
2841     }
2842 
2843   /* code for nontrivial group */
2844 
2845     else
2846     {
2847         nb0 = (EDGE**)numbering[0];
2848         nbop = (EDGE**)numbering[numb_pres == 0 ? numb_total : numb_pres];
2849         nblim = (EDGE**)numbering[numb_total];
2850 
2851         for (i = 0; i < ne; ++i) nb0[i]->index = i;
2852 
2853         RESETMARKS;
2854 
2855         k = 0;
2856         for (i = 0; i < ne; ++i)
2857         {
2858             e = nb0[i];
2859             if (ISMARKEDLO(e)) continue;
2860             ext3[k++] = e;
2861 
2862             for (nb1 = nb0 + i; nb1 < nbop; nb1 += MAXE) MARKLO(*nb1);
2863 
2864             for (; nb1 < nblim; nb1 += MAXE) MARKLO((*nb1)->invers);
2865 
2866             e1 = e->invers->prev;
2867             for (nb1 = nb0 + e1->index; nb1 < nbop; nb1 += MAXE) MARKLO(*nb1);
2868 
2869             for (; nb1 < nblim; nb1 += MAXE) MARKLO((*nb1)->invers);
2870 
2871             e1 = e1->invers->prev;
2872             for (nb1 = nb0 + e1->index; nb1 < nbop; nb1 += MAXE) MARKLO(*nb1);
2873 
2874             for (; nb1 < nblim; nb1 += MAXE) MARKLO((*nb1)->invers);
2875         }
2876         *numext3 = k;
2877 
2878         if (deg3 <= 2 && !Aswitch)
2879         {
2880             RESETMARKS;
2881 
2882             k = 0;
2883             for (i = 0; i < ne; ++i)
2884             {
2885                 e = nb0[i];
2886                 if (ISMARKEDLO(e)) continue;
2887                 e1 = e->next->invers->prev;
2888                 if ((degree[e->end] == 3) + (degree[e1->end] == 3) != deg3)
2889                     continue;
2890                 ext4[k++] = e;
2891 
2892                 for (nb1 = nb0 + i; nb1 < nbop; nb1 += MAXE) MARKLO(*nb1);
2893 
2894                 for (; nb1 < nblim; nb1 += MAXE) MARKLO((*nb1)->prev->prev);
2895 
2896                 for (nb1 = nb0 + e1->index; nb1 < nbop; nb1 += MAXE)
2897                     MARKLO(*nb1);
2898 
2899                 for (; nb1 < nblim; nb1 += MAXE) MARKLO((*nb1)->prev->prev);
2900             }
2901             *numext4 = k;
2902         }
2903         else
2904             *numext4 = 0;
2905 
2906         if (deg3 == 0 && deg4 <= 2 && !Aswitch)
2907         {
2908             RESETMARKS;
2909 
2910             k = 0;
2911             for (i = 0; i < ne; ++i)
2912             {
2913                 e = nb0[i];
2914                 if (ISMARKEDLO(e) || degree[e->start] < 6) continue;
2915 
2916                 if ((degree[e->end] == 4)
2917                        + (degree[e->next->next->next->end] == 4) != deg4)
2918                     continue;
2919                 ext5[k++] = e;
2920 
2921                 for (nb1 = nb0 + i; nb1 < nbop; nb1 += MAXE) MARKLO(*nb1);
2922 
2923                 for (; nb1 < nblim; nb1 += MAXE)
2924                     MARKLO((*nb1)->prev->prev->prev);
2925             }
2926             *numext5 = k;
2927         }
2928         else
2929             *numext5 = 0;
2930     }
2931 }
2932 
2933 /**************************************************************************/
2934 
2935 static int
make_dual(void)2936 make_dual(void)
2937 
2938 /* Store in the rightface field of each edge the number of the face on
2939    the right hand side of that edge.  Faces are numbered 0,1,....  Also
2940    store in facestart[i] an example of an edge in the clockwise orientation
2941    of the face boundary, and the size of the face in facesize[i], for each i.
2942    Returns the number of faces. */
2943 {
2944     register int i,nf,sz;
2945     int nvlim;
2946     register EDGE *e,*ex,*ef,*efx;
2947 
2948     RESETMARKS;
2949 
2950     nvlim = nv + (missing_vertex >= 0);
2951     nf = 0;
2952     for (i = 0; i < nvlim; ++i)
2953     {
2954         if (i == missing_vertex) continue;
2955 
2956         e = ex = firstedge[i];
2957         do
2958         {
2959             if (!ISMARKEDLO(e))
2960             {
2961                 facestart[nf] = ef = efx = e;
2962                 sz = 0;
2963                 do
2964                 {
2965                     ef->rightface = nf;
2966                     MARKLO(ef);
2967                     ef = ef->invers->prev;
2968                     ++sz;
2969                 } while (ef != efx);
2970                 facesize[nf] = sz;
2971                 ++nf;
2972             }
2973             e = e->next;
2974         } while (e != ex);
2975     }
2976 
2977     return nf;
2978 }
2979 
2980 /**************************************************************************/
2981 
2982 static void
compute_edgecode(unsigned char code[],int * length,int * headerlength)2983 compute_edgecode(unsigned char code[], int *length, int *headerlength)
2984 
2985 /* Computes a code by numbering the edges and
2986    then listing them in code. Code consists of a header (of varying length
2987    -- see below) and a sequence of entries coding edge numbers and separators
2988    of length ne+nv-1. In this program unsigned char will always provide enough
2989    room to number the edges.
2990 
2991    We will first describe how the default code works:
2992    All entries are unsigned char. The first unsigned char encodes the
2993    length of the code that follows (so it is not including the 1 byte for
2994    the header). The numbers of the edges are 0 to 254
2995    and the byte 255 is always used as a separator between 2 lists of edges.
2996    The first segment from entry 2 (so the first non-header-entry) until the
2997    first separator contains
2998    the edges around vertex 1 in clockwise order. The second segment between
2999    the first separator and the second contains the edges around vertex 2 in
3000    clockwise order, etc. Every edgenumber occurs exactly twice.
3001 
3002    In case of a given directed starting edge in code_edge, this edge is
3003    numbered 0 and starts at the vertex corresponding to the first list.
3004 
3005    In plantri it can't happen (at the moment) that 254 is not enough to
3006    encode the edges, but it can happen that 255 is not sufficient to encode
3007    the length of the following code. In this case the first byte is 0 --
3008    meaning: interpret the second byte as information about sizes of
3009    the entries. The first 4 bits encode the number of bytes used to
3010    encode the codesize and the second 4 (those with lower value) encode
3011    the number of bytes used to encode the edge numbers. In plantri it will
3012    never be necessary to use more than 1 byte for the edgenumbers and 2
3013    for the codesize. So in case the first byte is 0, the second will
3014    always be (2<<4)+1. The separator is always one byte with value 255.
3015 
3016    A sequence of bytes will always be interpreted in a big-endian way. So
3017    the first byte is the most significant one. In order to be able to
3018    recognize separators in cases where more than 1 byte is used to encode
3019    edges, we never use numbers for the edges where the most significant
3020    8 bits are 1. So if n bytes are used for the edges, the largest number
3021    used is (1<<n)-1-(1<<(n-1)).
3022 */
3023 {
3024     register EDGE *run;
3025     int i,j, startvertex;
3026     int edgenumber, limitnv;
3027 
3028     RESETMARKS;
3029 
3030     if (missing_vertex>=0) limitnv=nv+1; else limitnv=nv;
3031 
3032     i=nv+ne-1;
3033 
3034     if (i<256) { *code=i; code++; *length=i+1; *headerlength=1;}
3035     else
3036       { *code=0; code++;
3037         *code=(2<<4)+1; code++;
3038 	*code=i>>8; code++;
3039 	*code=i&255; code++;
3040 	*headerlength=4;
3041 	*length=i+4;
3042       }
3043 
3044     if (code_edge==NULL) run=firstedge[0];
3045     else { run=code_edge; }
3046     startvertex=run->start;
3047     MARK(run->invers);
3048     run->invers->index=*code=0;
3049     code++; run=run->next;
3050 
3051     edgenumber = 1;
3052 
3053     for (j=1; j<degree[startvertex]; j++, run=run->next)
3054       {
3055 	if (ISMARKED(run)) { *code = run->index; code++; }
3056 	else {
3057 	       MARK(run->invers);
3058 	       run->invers->index= *code =edgenumber; code++;
3059 	       edgenumber++;
3060 	     }
3061       }
3062     *code=255; code++;
3063 
3064     for (i=0;i<limitnv;i++)
3065       if ((i!=startvertex) && (i!=missing_vertex))
3066 	{
3067 	  for (j=0, run=firstedge[i]; j<degree[i]; j++, run=run->next)
3068 	    {
3069 	      if (ISMARKED(run)) { *code = run->index; code++; }
3070 	      else {
3071 		MARK(run->invers);
3072 		run->invers->index=edgenumber;
3073 		*code=edgenumber; code++;
3074 		edgenumber++;
3075 	      }
3076 	    }
3077 	  *code=255;  code++;
3078 	}
3079     return;
3080 }
3081 
3082 /**************************************************************************/
3083 
3084 static void
compute_dual_edgecode(unsigned char code[],int * length,int * headerlength)3085 compute_dual_edgecode(unsigned char code[], int *length, int *headerlength)
3086 
3087 /* See compute_edgecode. It directly computes the code of the dual.
3088    In case code_edge is given, the first list of edges corresponds
3089    to the vertex representing the outer face.
3090 */
3091 
3092 {
3093     register EDGE *run, *start;
3094     int i,j ;
3095     int edgenumber, limitnv;
3096 
3097     RESETMARKS;
3098 
3099     if (missing_vertex>=0) limitnv=nv+1; else limitnv=nv;
3100 
3101     i=ne+(ne/2)-nv+1;
3102 
3103     if (i<256) { *code=i; code++; *length=i+1; *headerlength=1;}
3104     else
3105       { *code=0; code++;
3106         *code=(2<<4)+1; code++;
3107 	*code=i>>8; code++;
3108 	*code=i&255; code++;
3109 	*headerlength=4;
3110 	*length=i+4;
3111       }
3112 
3113     if (code_edge==NULL) start=firstedge[0];
3114     else { start=code_edge; }
3115     run=start;
3116     edgenumber=0;
3117     do
3118       {
3119 	if (ISMARKED(run)) { *code=run->index; code++; }
3120 	else /* so the other side has not yet been visited */
3121 	  {
3122 	    MARKLO(run->invers);
3123           /* numbered but left hand face not yet listed. In case of bridges it can even
3124 	     happen for the first face that the other side is already marked high.*/
3125 	  /* run->index is never used in the future */
3126 	    run->invers->index=*code=edgenumber; code++;
3127 	    edgenumber++;
3128 	  }
3129 	MARKHI(run); /* is numbered and face on the left has already been listed */
3130 	run=run->prev->invers;
3131       } while (run!=start);
3132     *code=255; code++;
3133 
3134     /* that was to make sure that in the case of disc triangulations the right start
3135        is taken -- now the rest */
3136 
3137 
3138     for (i=0;i<limitnv;i++)
3139       if (i!=missing_vertex)
3140       for (j=0, start=firstedge[i]; j<degree[i]; j++, start=start->next)
3141 	if (!ISMARKEDHI(start))/* a new face to be coded */
3142 	    {  run=start;
3143 	    do
3144 	      {
3145 		if (ISMARKED(run)) { *code=run->index; code++;}
3146 		else /* so the other side has not yet been visited */
3147 		  {
3148 		  MARKLO(run->invers);
3149 		  run->invers->index=*code=edgenumber; code++;
3150 		  edgenumber++;
3151 		  }
3152 		MARKHI(run);
3153 		run=run->prev->invers;
3154 	      } while (run!=start);
3155 	    *code=255; code++;
3156 	    }
3157     return;
3158 }
3159 
3160 /**************************************************************************/
3161 
3162 static void
mirror_of_edgecode(unsigned char newcode[],unsigned char oldcode[],int preserve,int totallength,int headerlength)3163 mirror_of_edgecode(unsigned char newcode[], unsigned char oldcode[],
3164 			int preserve, int totallength, int headerlength)
3165 {
3166   /* copies oldcode to newcode by reversing the rotational order inside
3167      the lists. In case "preserve" is not 0, it is made sure that the
3168      face on the left hand side of edge 1 starting at the vertex corresponding
3169      to the first list is the same afterwards when interpreting the output
3170      in clockwise order both times
3171 
3172      In case of "preserve" the routine relies on the first entry of oldcode
3173      except the vertexnumber being 1. This is guaranteed by compute_edgecode.
3174 
3175 */
3176 
3177   int i, number[MAXE/2];
3178   unsigned char *run,*start,*end, *last;
3179 
3180   last=newcode+totallength;
3181 
3182   for (i=0;i<headerlength;i++) newcode[i]=oldcode[i];
3183 
3184   if (!preserve)
3185     { newcode+=headerlength;
3186       start=end=oldcode+headerlength-1;
3187       while(newcode<last)
3188 	{
3189 	  for (run=end+1; *run!=255; run++);
3190 	  end=run;
3191 	  for (run--; run!=start; run--, newcode++) *newcode=*run;
3192 	  *newcode=255; newcode++;
3193 	  start=end;
3194 	}
3195       return;
3196     }
3197 
3198   /* else -- do preserve the face */
3199 
3200   for (i=0; i<ne/2; i++) number[i]=i;
3201   if (oldcode[headerlength]!=0)
3202     { fprintf(stderr,"Problem in mirror_of_edgecode -- read function description.\n");
3203       exit(1); }
3204   for (run=oldcode+headerlength;*run!=255;run++);
3205   end=run;
3206   run--;
3207   number[0]=*run; number[*run]=0;
3208   newcode+=headerlength;
3209   for ( ; run!=(oldcode+headerlength-1); run--) { *newcode=number[*run]; newcode++; }
3210   *newcode=255; newcode++;
3211   start=end;
3212 
3213   while(newcode<last)
3214     {
3215       for (run=end+1; *run!=255; run++);
3216       end=run;
3217       for ( run--; run!=start; run--, newcode++) *newcode=number[*run];
3218       *newcode=255; newcode++;
3219       start=end;
3220     }
3221   return;
3222 
3223 }
3224 
3225 /**************************************************************************/
3226 
3227 static void
write_edgecode(FILE * f,int doflip)3228 write_edgecode(FILE *f, int doflip)
3229 
3230 /* Write in edge_code format.  Always write in next direction,
3231    and if doflip != 0 also write in prev direction. */
3232 {
3233     int length, headerlength;
3234     unsigned char code[MAXN+MAXE+4];
3235     unsigned char mirrorcode[MAXN+MAXE+4];
3236 
3237 
3238       if ((ne/2)>UCHAR_MAX)
3239 	{ fprintf(stderr,
3240              ">E %s: Output routine write_edgecode not prepared for ",cmdname);
3241 	  fprintf(stderr,"that many edges\n");
3242 	  exit(1);
3243 	}
3244 
3245     compute_edgecode(code,&length,&headerlength);
3246 
3247     if (fwrite(code,sizeof(unsigned char),length,f) != length)
3248     {
3249         fprintf(stderr,">E %s: fwrite() failed\n",cmdname);
3250         perror(">E ");
3251         exit(1);
3252     }
3253     if (doflip)
3254       { mirror_of_edgecode(mirrorcode, code, (code_edge!=NULL), length, headerlength);
3255         if (fwrite(mirrorcode,sizeof(unsigned char),length,f) != length)
3256 	  {
3257 	    fprintf(stderr,">E %s: fwrite() failed\n",cmdname);
3258 	    perror(">E ");
3259 	    exit(1);
3260 	  }
3261       }
3262 }
3263 
3264 static void
write_dual_edgecode(FILE * f,int doflip)3265 write_dual_edgecode(FILE *f, int doflip)
3266 
3267 /* Write in edge_code format.  Always write in next direction,
3268    and if doflip != 0 also write in prev direction. */
3269 {
3270     int length, headerlength;
3271     unsigned char code[MAXF+MAXE+4], mirrorcode[MAXF+MAXE+4];
3272 
3273 
3274       if ((ne/2)>UCHAR_MAX)
3275 	{ fprintf(stderr,
3276          ">E %s: Output routine write_dual_edgecode not prepared for ",cmdname);
3277 	  fprintf(stderr,"that many edges\n");
3278 	  exit(1);
3279 	}
3280 
3281     compute_dual_edgecode(code,&length,&headerlength);
3282     if (fwrite(code,sizeof(unsigned char),length,f) != length)
3283     {
3284         fprintf(stderr,">E %s: fwrite() failed\n",cmdname);
3285         perror(">E ");
3286         exit(1);
3287     }
3288     if (doflip)
3289       { mirror_of_edgecode(mirrorcode, code, 0,length,headerlength);
3290         if (fwrite(mirrorcode,sizeof(unsigned char),length,f) != length)
3291 	  {
3292 	    fprintf(stderr,">E %s: fwrite() failed\n",cmdname);
3293 	    perror(">E ");
3294 	    exit(1);
3295 	  }
3296       }
3297 }
3298 
3299 /**************************************************************************/
3300 
3301 static void
write_double_code(FILE * f,int doflip)3302 write_double_code(FILE *f, int doflip)
3303 
3304 /* Write both the primal and code graphs in edge_code using A,B,C,... for
3305    edges.  This uses the switch dswitch to determine which of the two codes
3306    is written first. */
3307 {
3308     unsigned char code[MAXN+MAXE+MAXF+6];
3309     int i,nvlim,edgename,len,nf,pass,first;
3310     EDGE *e,*elast,*ee,*eelast;
3311 
3312     if (ne/2 >= 189)
3313     {
3314         fprintf(stderr,
3315          ">E %s: Output routine write_double_code not prepared for ",cmdname);
3316 	  fprintf(stderr,"that many edges\n");
3317 	  exit(1);
3318     }
3319 
3320     nvlim = (missing_vertex < 0 ? nv : nv+1);
3321     nf = 2 + (ne/2) - nv;
3322 
3323     RESETMARKS;
3324     edgename = 'A';
3325 
3326     for (i = 0; i < nvlim; ++i)
3327     {
3328 	if (i == missing_vertex) continue;
3329 
3330 	e = elast = firstedge[i];
3331 	do
3332 	{
3333 	    if (!ISMARKED(e->min))
3334 	    {
3335 		e->rf = e->invers->rf = edgename;
3336 		edgename++;
3337 		MARK(e->min);
3338 	    }
3339 	    e = e->next;
3340 	} while (e != elast);
3341     }
3342 
3343     len = 0;
3344 
3345     for (pass = 0; pass < 2; ++pass)
3346     {
3347 	if ((!dswitch && pass == 0) || (dswitch && pass == 1))
3348 	{
3349 	      /* primal */
3350 
3351 	    if (nv >= 100) code[len++] = '0' + (nv/100);
3352             if (nv >= 10) code[len++] = '0' + ((nv/10)%10);
3353             code[len++] = '0' + (nv%10);
3354             code[len++] = ' ';
3355 
3356 	    first = TRUE;
3357 	    for (i = 0; i < nvlim; ++i)
3358 	    {
3359 		if (i == missing_vertex) continue;
3360 
3361 		if (!first) code[len++] = ' ';
3362 		else first = FALSE;
3363 
3364 		e = elast = firstedge[i];
3365 		do
3366 		{
3367 		    code[len++] = e->rf;
3368 		    e = e->next;
3369 		} while (e != elast);
3370 	    }
3371 	}
3372 	else
3373 	{
3374 	      /* dual */
3375 
3376 	    if (nf >= 100) code[len++] = '0' + (nf/100);
3377             if (nf >= 10) code[len++] = '0' + ((nf/10)%10);
3378             code[len++] = '0' + (nf%10);
3379             code[len++] = ' ';
3380 
3381 	    RESETMARKS;
3382 	    first = TRUE;
3383 	    for (i = 0; i < nvlim; ++i)
3384 	    {
3385 		if (i == missing_vertex) continue;
3386 
3387 		e = elast = firstedge[i];
3388 		do
3389 		{
3390 		    if (!ISMARKED(e))
3391 		    {
3392 		        if (!first) code[len++] = ' ';
3393 		        else first = FALSE;
3394 
3395 			ee = eelast = e;
3396 			do
3397 			{
3398 			    MARK(ee);
3399 			    code[len++] = ee->rf;
3400 			    ee = ee->invers->prev;
3401 			} while (ee != eelast);
3402                     }
3403                     e = e->next;
3404 		} while (e != elast);
3405 	    }
3406 	}
3407 
3408 	code[len++] = (pass == 0 ? ' ' : '\n');
3409     }
3410 
3411     if (fwrite(code,sizeof(unsigned char),len,f) != len)
3412     {
3413         fprintf(stderr,">E %s: fwrite() failed\n",cmdname);
3414         perror(">E ");
3415         exit(1);
3416     }
3417 
3418     if (!doflip) return;
3419 
3420     len = 0;
3421 
3422     for (pass = 0; pass < 2; ++pass)
3423     {
3424 	if ((!dswitch && pass == 0) || (dswitch && pass == 1))
3425 	{
3426 	      /* primal */
3427 
3428 	    if (nv >= 100) code[len++] = '0' + (nv/100);
3429             if (nv >= 10) code[len++] = '0' + ((nv/10)%10);
3430             code[len++] = '0' + (nv%10);
3431             code[len++] = ' ';
3432 
3433 	    first = TRUE;
3434 	    for (i = 0; i < nvlim; ++i)
3435 	    {
3436 		if (i == missing_vertex) continue;
3437 
3438 		if (!first) code[len++] = ' ';
3439 		else first = FALSE;
3440 
3441 		e = elast = firstedge[i];
3442 		do
3443 		{
3444 		    code[len++] = e->rf;
3445 		    e = e->prev;
3446 		} while (e != elast);
3447 	    }
3448 	}
3449 	else
3450 	{
3451 	      /* dual */
3452 
3453 	    if (nf >= 100) code[len++] = '0' + (nf/100);
3454             if (nf >= 10) code[len++] = '0' + ((nf/10)%10);
3455             code[len++] = '0' + (nf%10);
3456             code[len++] = ' ';
3457 
3458 	    RESETMARKS;
3459 	    first = TRUE;
3460 	    for (i = 0; i < nvlim; ++i)
3461 	    {
3462 		if (i == missing_vertex) continue;
3463 
3464 		e = elast = firstedge[i];
3465 		do
3466 		{
3467 		    if (!ISMARKED(e))
3468 		    {
3469 		        if (!first) code[len++] = ' ';
3470 		        else first = FALSE;
3471 
3472 			ee = eelast = e;
3473 			do
3474 			{
3475 			    MARK(ee);
3476 			    code[len++] = ee->rf;
3477 			    ee = ee->invers->next;
3478 			} while (ee != eelast);
3479                     }
3480                     e = e->prev;
3481 		} while (e != elast);
3482 	    }
3483 	}
3484 
3485 	code[len++] = (pass == 0 ? ' ' : '\n');
3486     }
3487 
3488     if (fwrite(code,sizeof(unsigned char),len,f) != len)
3489     {
3490         fprintf(stderr,">E %s: fwrite() failed\n",cmdname);
3491         perror(">E ");
3492         exit(1);
3493     }
3494 }
3495 
3496 /**************************************************************************/
3497 
3498 static void
compute_code(unsigned char code[])3499 compute_code(unsigned char code[])
3500 
3501 /* computes a code by numbering the vertices in a breadth first manner and
3502    then listing them in code. Code is a sequence of numbers of length ne+nv+1.
3503    The first entry is the number of vertices.
3504    Then the numbers of the vertices adjacent to the vertex numbered 1 are
3505    given -- ended by a 0, and listed in clockwise orientation.
3506    Then those adjacent to 2, ended by a 0, etc. . In case of no
3507    double edges, the identification of the corresponding "half edges" leaving
3508    each vertex is unique. Nevertheless also for this case the following rules
3509    apply (not in the definition of the code, but in this routine):
3510 
3511    In case of double edges, the first time a new vertex
3512    b occurs in the list, say it is in the list of vertex a, must be matched
3513    with the first occurence of vertex a in the list of b. In this routine
3514    it will always be the first position in the list of b.
3515 
3516    This spanning tree
3517    gives a unique matching for the other "half edges" -- provided the fact
3518    that the ordering comes from an embedding on the sphere.
3519 
3520    In case of a given starting edge in code_edge, the start of this
3521    edge is numbered 1 and the end 2.
3522 */
3523 {
3524     register EDGE *run;
3525     register int vertex;
3526     EDGE *temp;
3527     EDGE *startedge[MAXN+1];
3528     int number[MAXN+1], i;
3529     int last_number, actual_number;
3530     EDGE *givenedge;
3531 
3532     for (i = 0; i < nv; i++) number[i] = 0;
3533 
3534     *code=nv; code++;
3535     if (code_edge==NULL) givenedge=firstedge[0];
3536     else { givenedge=code_edge; number[nv]=0; }
3537     number[givenedge->start] = 1;
3538     if (givenedge->start != givenedge->end)
3539       {
3540 	number[givenedge->end] = 2;
3541 	last_number = 2;
3542 	startedge[1] = givenedge->invers;
3543       }
3544     else  last_number = 1;
3545 
3546     actual_number = 1;
3547     temp = givenedge;
3548 
3549     while (last_number < nv)
3550     {   *code=number[temp->end]; code++;
3551         for (run = temp->next; run != temp; run = run->next)
3552           { vertex = run->end;
3553             if (!number[vertex])
3554               { startedge[last_number] = run->invers;
3555                 last_number++; number[vertex] = last_number;
3556                 *code = last_number; }
3557             else *code = number[vertex];
3558             code++;
3559           }
3560         *code = 0;  code++;
3561         temp = startedge[actual_number];  actual_number++;
3562     }
3563 
3564     while (actual_number <= nv)
3565     {  	*code=number[temp->end]; code++;
3566         for (run = temp->next; run != temp; run = run->next)
3567           {
3568             *code = number[run->end]; code++;
3569           }
3570         *code = 0;
3571         code++;
3572         temp = startedge[actual_number];  actual_number++;
3573     }
3574 }
3575 
3576 /****************************************************************************/
3577 
3578 static void
compute_code_mirror(unsigned char code[])3579 compute_code_mirror(unsigned char code[])
3580 
3581 /* In the case of no double edges -- that is when the identifications are
3582    clear -- there is no problem in just returning the inverse order of
3583    the previously computed code. Nevertheless in the case where edge
3584    identifications must be made via the spanning tree described in the code,
3585    this is not that easy, so we can as well just compute mirror code just
3586    like the normal code computed before.
3587 
3588    In case code_edge is not NULL, its start is numbered 1 and its
3589    end is numbered 0.
3590 */
3591 {
3592     register EDGE *run;
3593     register int vertex;
3594     EDGE *temp;
3595     EDGE *startedge[MAXN+1];
3596     int number[MAXN+1], i;
3597     int last_number, actual_number;
3598     EDGE *givenedge;
3599 
3600     for (i = 0; i < nv; i++) number[i] = 0;
3601 
3602     *code=nv; code++;
3603     if (code_edge==NULL) givenedge=firstedge[0];
3604     else { givenedge=code_edge->invers; number[nv]=0; }
3605     number[givenedge->start] = 1;
3606     if (givenedge->start != givenedge->end)
3607       {
3608 	number[givenedge->end] = 2;
3609 	last_number = 2;
3610 	startedge[1] = givenedge->invers;
3611       }
3612     else  last_number = 1;
3613 
3614     actual_number = 1;
3615     temp = givenedge;
3616 
3617     while (last_number < nv)
3618     {   *code=number[temp->end]; code++;
3619         for (run = temp->prev; run != temp; run = run->prev)
3620           { vertex = run->end;
3621             if (!number[vertex])
3622               { startedge[last_number] = run->invers;
3623                 last_number++; number[vertex] = last_number;
3624                 *code = last_number; }
3625             else *code = number[vertex];
3626             code++;
3627           }
3628         *code = 0;  code++;
3629         temp = startedge[actual_number];  actual_number++;
3630     }
3631 
3632     while (actual_number <= nv)
3633     {  	*code=number[temp->end]; code++;
3634         for (run = temp->prev; run != temp; run = run->prev)
3635           {
3636             *code = number[run->end]; code++;
3637           }
3638         *code = 0;
3639         code++;
3640         temp = startedge[actual_number];  actual_number++;
3641     }
3642 }
3643 
3644 /****************************************************************************/
3645 
3646 static void
compute_dual_code(unsigned char code[])3647 compute_dual_code(unsigned char code[])
3648 
3649 /* works like compute_code -- only for the dual */
3650 
3651 {
3652     register EDGE *run, *run2;
3653     EDGE *temp;
3654     EDGE *startedge[MAXF+1];
3655     /* int i, number[MAXF+1]; */
3656     int last_number, actual_number;
3657     int nf;
3658     EDGE *givenedge;
3659 
3660     nf=2+(ne/2)-nv;
3661     *code=nf; code++;
3662     RESETMARKS; /* The face on the right has already been numbered if
3663 		   and only if it is marked. */
3664     /* for (i = 0; i < nf; i++) number[i] = 0; */
3665 
3666     if (code_edge==NULL) givenedge=firstedge[0];
3667     else givenedge=code_edge->invers;
3668 
3669     run=givenedge;
3670     do { MARKLO(run); run->rf=1; run=run->invers->prev;
3671        } while (run!=givenedge);
3672     if (!ISMARKED(givenedge->invers)) /* no loop in the dual at this point */
3673       { run2=run=givenedge->invers;
3674         do { MARKLO(run2); run2->rf=2; run2=run2->invers->prev;
3675            } while (run2!=run);
3676 	last_number = 2;
3677 	startedge[1] = givenedge; /* the startedge has the face it belongs
3678 				     to on the LEFT */
3679       }
3680     else  last_number = 1;
3681 
3682     actual_number = 1;
3683     temp = givenedge->invers;
3684     while (last_number < nf)
3685     {
3686         *code= temp->rf; code++;
3687         for (run = temp->prev->invers; run != temp; run = run->prev->invers)
3688 	  /* run also has the face it runs around on the left */
3689           { if (!ISMARKED(run))
3690 	    { startedge[last_number] = run->invers;
3691               last_number++;
3692 	      run2=run;
3693 	      do
3694 		{ MARKLO(run2);
3695 		  run2->rf=last_number;
3696 		  run2=run2->invers->prev;
3697                 } while (run2!=run);
3698 	      *code = last_number;
3699 	    }
3700 	    else *code=run->rf;
3701 	    code++;
3702 	  }
3703         *code = 0;  code++;
3704         temp = startedge[actual_number];  actual_number++;
3705     }
3706 
3707     while (actual_number <= nf)
3708     {  	*code=temp->rf; code++;
3709         for (run = temp->prev->invers; run != temp; run = run->prev->invers)
3710           {
3711             *code = run->rf; code++;
3712           }
3713         *code = 0;
3714         code++;
3715         temp = startedge[actual_number];  actual_number++;
3716     }
3717 }
3718 
3719 /****************************************************************************/
3720 
3721 static void
compute_dual_code_mirror(unsigned char code[])3722 compute_dual_code_mirror(unsigned char code[])
3723 
3724 /* works like compute_code_mirror -- only for the dual */
3725 
3726 {
3727     register EDGE *run, *run2;
3728     EDGE *temp;
3729     EDGE *startedge[MAXF+1];
3730     /* int i, number[MAXF+1]; */
3731     int last_number, actual_number;
3732     int nf;
3733     EDGE *givenedge;
3734 
3735     nf=2+(ne/2)-nv;
3736     *code=nf; code++;
3737     RESETMARKS; /* The face on the right has already been numbered
3738                    if and only if it is marked. */
3739     /* for (i = 0; i < nf; i++) number[i] = 0; */
3740 
3741     if (code_edge==NULL) givenedge=firstedge[0];
3742     else givenedge=code_edge->invers;
3743 
3744     run=givenedge;
3745     do { MARKLO(run); run->rf=1; run=run->invers->prev;
3746        } while (run!=givenedge);
3747     if (!ISMARKED(givenedge->invers)) /* no loop in the dual at this point */
3748       { run2=run=givenedge->invers;
3749         do { MARKLO(run2); run2->rf=2; run2=run2->invers->prev;
3750            } while (run2!=run);
3751 	last_number = 2;
3752 	startedge[1] = givenedge; /* the startedge has the face it
3753 				     belongs to on the LEFT */
3754       }
3755     else  last_number = 1;
3756 
3757     actual_number = 1;
3758     temp = givenedge->invers;
3759 
3760     while (last_number < nf)
3761     {
3762         *code= temp->rf; code++;
3763         for (run = temp->invers->next; run != temp; run = run->invers->next)
3764 	  /* run also has the face it runs around on the left */
3765           { if (!ISMARKED(run))
3766 	    { startedge[last_number] = run->invers;
3767               last_number++;
3768 	      run2=run;
3769 	      do
3770 		{ MARKLO(run2); run2->rf=last_number;
3771 		  run2=run2->invers->prev;
3772                 } while (run2!=run);
3773 	      *code = last_number;
3774 	    }
3775 	  else *code=run->rf;
3776 	  code++;
3777 	  }
3778         *code = 0;  code++;
3779         temp = startedge[actual_number];  actual_number++;
3780     }
3781 
3782     while (actual_number <= nf)
3783     {  	*code=temp->rf; code++;
3784         for (run = temp->invers->next; run != temp; run = run->invers->next)
3785           {
3786             *code = run->rf; code++;
3787           }
3788         *code = 0;
3789         code++;
3790         temp = startedge[actual_number];  actual_number++;
3791     }
3792 }
3793 
3794 /**************************************************************************/
3795 
3796 static void
write_planar_code(FILE * f,int doflip)3797 write_planar_code(FILE *f, int doflip)
3798 
3799 /* Write in planar_code format.  Always write in next direction,
3800    and if doflip != 0 also write in prev direction. */
3801 {
3802     size_t length;
3803     unsigned char code[MAXN+MAXE+1];
3804 
3805     length=nv+ne+1;
3806     compute_code(code);
3807     if (fwrite(code,sizeof(unsigned char),length,f) != length)
3808     {
3809         fprintf(stderr,">E %s: fwrite() failed\n",cmdname);
3810         perror(">E ");
3811         exit(1);
3812     }
3813     if (doflip)
3814       { compute_code_mirror(code);
3815         if (fwrite(code,sizeof(unsigned char),length,f) != length)
3816 	  {
3817 	    fprintf(stderr,">E %s: fwrite() failed\n",cmdname);
3818 	    perror(">E ");
3819 	    exit(1);
3820 	  }
3821       }
3822 }
3823 
3824 /**************************************************************************/
3825 
3826 static void
write_dual_planar_code(FILE * f,int doflip)3827 write_dual_planar_code(FILE *f, int doflip)
3828 
3829 /* Write the dual in planar_code format.  Always write in next direction,
3830    and if doflip != 0 also write in prev direction. */
3831 {
3832     size_t length;
3833     unsigned char code[MAXF+MAXE+1];
3834 
3835     length=3+ne+(ne/2)-nv;
3836     compute_dual_code(code);
3837     if (fwrite(code,sizeof(unsigned char),length,f) != length)
3838     {
3839         fprintf(stderr,">E %s: fwrite() failed\n",cmdname);
3840         perror(">E ");
3841         exit(1);
3842     }
3843     if (doflip)
3844       { compute_dual_code_mirror(code);
3845       if (fwrite(code,sizeof(unsigned char),length,f) != length)
3846 	{
3847 	  fprintf(stderr,">E %s: fwrite() failed\n",cmdname);
3848 	  perror(">E ");
3849 	  exit(1);
3850 	}
3851       }
3852 }
3853 
3854 
3855 /**************************************************************************/
3856 
3857 static void
write_digits(FILE * f,int doflip)3858 write_digits(FILE *f, int doflip)
3859 
3860 /* Write in alphabetic format.  Always write in next direction,
3861    and if doflip != 0 also write in prev direction.  This output
3862    procedure uses the internal numbering of vertices and is
3863    intended for debugging purposes. */
3864 {
3865     int i,k;
3866     EDGE *ex,*e;
3867     unsigned char code[2*MAXN+2*MAXE+9];
3868     int nvsize;
3869     int lastnum,w;
3870     int nbop,nbtot,nbpart;
3871     EDGE **nb0,**nb,**nblim;
3872 #define CODE0(x) ((x)<10 ? '0'+(x) : 'a'+(x)-10)
3873 
3874     if (oneswitch)
3875     {
3876 	nbop = gotone_nbop;
3877 	nbtot = gotone_nbtot;
3878 	nbpart = (nbop==0 || nbop==nbtot ? nbtot : nbop);
3879 	fprintf(f,"%d %d %d %d %d\n",nv,ne,(doflip?2:1),nbpart,nbtot);
3880 
3881 	nb0 = (EDGE**) numbering[0];
3882 	nblim = (EDGE**) numbering[doflip ? nbpart : nbtot];
3883 
3884 	if (nblim != (EDGE**) numbering[1])
3885 	    for (nb = nb0; nb < nblim; nb += MAXE)
3886 	    {
3887 		for (i = 0; i < ne; ++i)
3888 		    fprintf(f," %c%c",CODE0(nb[i]->start),CODE0(nb[i]->end));
3889 		fprintf(f,"\n");
3890 	    }
3891     }
3892 
3893     if (nv >= 10)
3894     {
3895         code[0] = '0' + nv/10;
3896         code[1] = '0' + nv%10;
3897         code[2] = ' ';
3898         nvsize = k = 3;
3899     }
3900     else
3901     {
3902         code[0] = '0' + nv;
3903         code[1] = ' ';
3904         nvsize = k = 2;
3905     }
3906 
3907     if (missing_vertex < 0) lastnum = nv-1;
3908     else                    lastnum = nv;
3909 
3910     for (i = 0; i <= lastnum; ++i)
3911     {
3912 	if (i != missing_vertex)
3913 	{
3914             e = ex = firstedge[i];
3915             do
3916             {
3917 		w = e->end;
3918 		code[k++] = CODE0(w);
3919                 e = e->next;
3920             }
3921             while (e != ex);
3922             code[k++] = ',';
3923 	}
3924     }
3925     code[k-1] = '\n';
3926 
3927     if (doflip)
3928     {
3929         for (i = 0; i <nvsize; ++i) code[k++] = code[i];
3930 
3931         for (i = 0; i <= lastnum; ++i)
3932         {
3933 	    if (i != missing_vertex)
3934             {
3935                 e = ex = firstedge[i];
3936                 do
3937                 {
3938                     w = e->end;
3939 		    code[k++] = CODE0(w);
3940                     e = e->prev;
3941                 }
3942                 while (e != ex);
3943                 code[k++] = ',';
3944 	    }
3945         }
3946     }
3947     code[k-1] = '\n';
3948 
3949     if (fwrite(code,(size_t)1,(size_t)k,f) != (size_t)k)
3950     {
3951         fprintf(stderr,">E %s: fwrite() failed\n",cmdname);
3952         perror(">E ");
3953         exit(1);
3954     }
3955 }
3956 
3957 /**************************************************************************/
3958 
3959 static void
write_alpha(FILE * f,int doflip)3960 write_alpha(FILE *f, int doflip)
3961 
3962 /* Write in alphabetic format.  Always write in next direction,
3963    and if doflip != 0 also write in prev direction. */
3964 {
3965     int i, j, start;
3966     unsigned char code[MAXN+MAXE+4];
3967     unsigned char precode[MAXN+MAXE+1];
3968     size_t length;
3969 
3970     length=nv+ne;
3971     compute_code(precode);
3972 
3973     if (nv >= 10)
3974     {
3975         code[0] = '0' + nv/10;
3976         code[1] = '0' + nv%10;
3977         code[2] = ' ';
3978         length += 3;
3979 	start=3;
3980     }
3981     else
3982     {
3983         code[0] = '0' + nv;
3984         code[1] = ' ';
3985         length += 2;
3986 	start=2;
3987     }
3988 
3989     for (i = 1, j=start; j < length; ++i, ++j)
3990 	if (precode[i]==0) code[j]=',';
3991         else code[j]=precode[i]-1+'a';
3992 
3993     code[j-1]='\n';
3994     if (fwrite(code,sizeof(unsigned char),length,f) != length)
3995     {
3996         fprintf(stderr,">E %s: fwrite() failed\n",cmdname);
3997         perror(">E ");
3998         exit(1);
3999     }
4000     if (doflip)
4001       { compute_code_mirror(precode);
4002         for (i = 1, j=start; j < length; ++i, ++j)
4003 	    if (precode[i]==0) code[j]=',';
4004             else code[j]=precode[i]-1+'a';
4005         code[j-1]='\n';
4006         if (fwrite(code,sizeof(unsigned char),length,f) != length)
4007 	  {
4008 	    fprintf(stderr,">E %s: fwrite() failed\n",cmdname);
4009 	    perror(">E ");
4010 	    exit(1);
4011 	  }
4012       }
4013 }
4014 
4015 /**************************************************************************/
4016 
4017 static void
write_dual_alpha(FILE * f,int doflip)4018 write_dual_alpha(FILE *f, int doflip)
4019 
4020 /* Write the dual in alphabetic format.  Always write in next direction,
4021    and if doflip != 0 also write in prev direction. */
4022 {
4023     int i,j,start;
4024     unsigned char code[MAXN+MAXE+4];
4025     unsigned char precode[MAXN+MAXE+1];
4026     size_t length;
4027 
4028     length=2+ne+(ne/2)-nv;
4029     compute_dual_code(precode);
4030 
4031     if (precode[0] >= 10)
4032     {
4033         code[0] = '0' + precode[0]/10;
4034         code[1] = '0' + precode[0]%10;
4035         code[2] = ' ';
4036         length += 3;
4037 	start=3;
4038     }
4039     else
4040     {
4041         code[0] = '0' + precode[0];
4042         code[1] = ' ';
4043         length += 2;
4044 	start=2;
4045     }
4046 
4047     for (i = 1, j=start; j < length; ++i, ++j)
4048         if (precode[i]==0) code[j]=',';
4049         else code[j]=precode[i]-1+'a';
4050 
4051     code[j-1]='\n';
4052     if (fwrite(code,sizeof(unsigned char),length,f) != length)
4053     {
4054         fprintf(stderr,">E %s: fwrite() failed\n",cmdname);
4055         perror(">E ");
4056         exit(1);
4057     }
4058     if (doflip)
4059       { compute_dual_code_mirror(precode);
4060         for (i = 1, j=start; j < length; ++i, ++j)
4061 	    if (precode[i]==0) code[j]=',';
4062             else code[j]=precode[i]-1+'a';
4063         code[j-1]='\n';
4064         if (fwrite(code,sizeof(unsigned char),length,f) != length)
4065 	  {
4066 	    fprintf(stderr,">E %s: fwrite() failed\n",cmdname);
4067 	    perror(">E ");
4068 	    exit(1);
4069 	  }
4070       }
4071 }
4072 
4073 /**************************************************************************/
4074 
4075 static void
write_code_as_sparse6(FILE * f,unsigned char code[])4076 write_code_as_sparse6(FILE *f, unsigned char code[])
4077 
4078 /* Write a graph represented in planar_code to a file in sparse6 format.
4079    The imbedding is lost but the vertex numbering is the same.  This
4080    does not use any global variables and works to 255 vertices. */
4081 
4082 {
4083     register unsigned char *pin,*pout;
4084     unsigned char s6[20+2*MAXE+2*MAXF];
4085     int n,nb,i,j,lastj,x,k,r,rr,topbit;
4086     int loopcount;
4087 
4088     pin = code;
4089     n = *pin++;
4090     pout = s6;
4091     *pout++ = ':';
4092 
4093     if (n <= 62)
4094         *pout++ = 63 + n;
4095     else
4096     {
4097         *pout++ = 63 + 63;
4098         *pout++ = 63 + 0;
4099         *pout++ = 63 + (n >> 6);
4100         *pout++ = 63 + (n & 0x3F);
4101     }
4102 
4103     for (i = n-1, nb = 0; i != 0 ; i >>= 1, ++nb) {}
4104     topbit = 1 << (nb-1);
4105     k = 6;
4106     x = 0;
4107 
4108     lastj = 0;
4109     for (j = 0; j < n; ++j)
4110     {
4111 	loopcount = 0;   /* The input code shows loops once from each end,
4112                             but we want each loop just once in sparse6. */
4113         while ((i = *pin++) != 0)
4114         {
4115 	    --i;
4116             if (i < j || (i == j && ((++loopcount)&1)))
4117             {
4118                 if (j == lastj)
4119                 {
4120                     x <<= 1;
4121                     if (--k == 0)
4122                     {
4123                         *pout++ = 63 + x;
4124                         k = 6;
4125                         x = 0;
4126                     }
4127                 }
4128                 else
4129                 {
4130                     x = (x << 1) | 1;
4131                     if (--k == 0)
4132                     {
4133                         *pout++ = 63 + x;
4134                         k = 6;
4135                         x = 0;
4136                     }
4137                     if (j > lastj+1)
4138                     {
4139                         for (r = 0, rr = j; r < nb; ++r, rr <<= 1)
4140                         {
4141                             if (rr & topbit) x = (x << 1) | 1;
4142                             else             x <<= 1;
4143                             if (--k == 0)
4144                             {
4145                                 *pout++ = 63 + x;
4146                                 k = 6;
4147                                 x = 0;
4148                             }
4149                         }
4150                         x <<= 1;
4151                         if (--k == 0)
4152                         {
4153                             *pout++ = 63 + x;
4154                             k = 6;
4155                             x = 0;
4156                         }
4157                     }
4158                     lastj = j;
4159                 }
4160                 for (r = 0, rr = i; r < nb; ++r, rr <<= 1)
4161                 {
4162                     if (rr & topbit) x = (x << 1) | 1;
4163                     else             x <<= 1;
4164                     if (--k == 0)
4165                     {
4166                         *pout++ = 63 + x;
4167                         k = 6;
4168                         x = 0;
4169                     }
4170                 }
4171             }
4172         }
4173     }
4174 
4175     if (k != 6) *pout++ = 63 + ((x << k) | ((1 << k) - 1));
4176 
4177     *pout++ = '\n';
4178     k = pout - s6;
4179 
4180     if (fwrite(s6,sizeof(unsigned char),(size_t)k,f) != k)
4181     {
4182         fprintf(stderr,">E %s: fwrite() failed\n",cmdname);
4183         perror(">E ");
4184         exit(1);
4185     }
4186 }
4187 
4188 /**************************************************************************/
4189 
4190 static void
write_sparse6(FILE * f,int doflip)4191 write_sparse6(FILE *f, int doflip)
4192 
4193 /* Write in sparse6 format.  doflip is ignored. */
4194 {
4195     unsigned char code[MAXN+MAXE+1];
4196 
4197     compute_code(code);
4198     write_code_as_sparse6(f,code);
4199 }
4200 
4201 /**************************************************************************/
4202 
4203 static void
write_dual_sparse6(FILE * f,int doflip)4204 write_dual_sparse6(FILE *f, int doflip)
4205 
4206 /* Write dual cubic graph in sparse6 format.  doflip is ignored. */
4207 {
4208     unsigned char code[MAXF+MAXE+1];
4209 
4210     compute_dual_code(code);
4211     write_code_as_sparse6(f,code);
4212 }
4213 
4214 /**************************************************************************/
4215 
4216 static void
write_code_as_graph6(FILE * f,unsigned char code[])4217 write_code_as_graph6(FILE *f, unsigned char code[])
4218 
4219 /* Write a graph represented in planar_code to a file in graph6 format.
4220    The imbedding is lost, loops are lost, and multiple edges are changed
4221    to one edge.  The vertex numbering is the same.  This does not use any
4222    global variables and works to 255 vertices. */
4223 
4224 {
4225     unsigned char g6[20+MAXF*(MAXF-1)/12];
4226     register unsigned char *pin,*pout;
4227     int n,nlen,bodylen,i,j,org;
4228     static unsigned char g6bit[] = {32,16,8,4,2,1};
4229 
4230     pin = code;
4231     n = *pin++;
4232 
4233     if (n <= 62)
4234     {
4235         g6[0] = 63 + n;
4236         nlen = 1;
4237     }
4238     else
4239     {
4240         g6[0] = 63 + 63;
4241         g6[1] = 63 + 0;
4242         g6[2] = 63 + (n >> 6);
4243         g6[3] = 63 + (n & 0x3F);
4244         nlen = 4;
4245     }
4246 
4247     pout = g6 + nlen;
4248     bodylen = ((n * (n-1)) / 2 + 5) / 6;
4249     for (i = 0; i < bodylen; ++i) pout[i] = 0;
4250     pout[bodylen] = '\n';
4251 
4252     for (i = 0, org = -1; i < n; org += i, ++i)
4253     {
4254         while ((j = *pin++) != 0)
4255         {
4256             if (j <= i)
4257             {
4258                 j += org;
4259                 pout[j/6] |= g6bit[j%6];
4260             }
4261         }
4262     }
4263 
4264     for (i = 0; i < bodylen; ++i) pout[i] += 63;
4265 
4266     j = nlen + bodylen + 1;
4267     if (fwrite(g6,sizeof(unsigned char),(size_t)j,f) != j)
4268     {
4269         fprintf(stderr,">E %s: fwrite() failed\n",cmdname);
4270         perror(">E ");
4271         exit(1);
4272     }
4273 }
4274 
4275 /**************************************************************************/
4276 
4277 static void
write_graph6(FILE * f,int doflip)4278 write_graph6(FILE *f, int doflip)
4279 
4280 /* Write in graph6 format.  doflip is ignored. */
4281 {
4282     unsigned char code[MAXN+MAXE+1];
4283 
4284     compute_code(code);
4285     write_code_as_graph6(f,code);
4286 }
4287 
4288 /**************************************************************************/
4289 
4290 static void
write_dual_graph6(FILE * f,int doflip)4291 write_dual_graph6(FILE *f, int doflip)
4292 
4293 /* Write dual cubic graph in graph6 format.  doflip is ignored. */
4294 {
4295     unsigned char code[MAXF+MAXE+1];
4296 
4297     compute_dual_code(code);
4298     write_code_as_graph6(f,code);
4299 }
4300 
4301 /**************************************************************************/
4302 
4303 static void
check_it(int code,int triang)4304 check_it(int code, int triang)
4305 
4306 /* Checks these properties:
4307    1. Degrees are correct.
4308    2. Faces are triangles (if triang)
4309    3. start and end fields are correct.
4310    4. min fields are ok.
4311    5. vertex numbers are in range.
4312 */
4313 
4314 {
4315     int i,j;
4316     EDGE *e;
4317 
4318     for (i = 0; i < nv; ++i)
4319     {
4320 	/*
4321         if (degree[i] < 3)
4322         {
4323             fprintf(stderr,">E degree error, code=%d\n",code);
4324             exit(1);
4325         }
4326 	*/
4327 
4328         e = firstedge[i];
4329         for (j = 0; j < degree[i]; ++j) e = e->next;
4330         if (e != firstedge[i])
4331         {
4332             fprintf(stderr,">E next error, code=%d\n",code);
4333             exit(1);
4334         }
4335 
4336         e = firstedge[i];
4337         for (j = 0; j < degree[i]; ++j) e = e->prev;
4338         if (e != firstedge[i])
4339         {
4340             fprintf(stderr,">E prev error, code=%d\n",code);
4341             exit(1);
4342         }
4343 
4344         e = firstedge[i];
4345         for (j = 0; j < degree[i]; ++j)
4346         {
4347             e = e->next;
4348             if (e->start != i)
4349             {
4350                 fprintf(stderr,">E start error, code=%d\n",code);
4351                 exit(1);
4352             }
4353 	    if (e->end < 0 || e->end >= nv)
4354             {
4355                 fprintf(stderr,">E end label error, code=%d\n",code);
4356                 exit(1);
4357             }
4358 	    if (e->end != e->invers->start)
4359             {
4360                 fprintf(stderr,">E invers label error, code=%d\n",code);
4361                 exit(1);
4362 	    }
4363             if (e->invers->end != i)
4364             {
4365                 fprintf(stderr,">E end error, code=%d\n",code);
4366                 exit(1);
4367             }
4368 	    if (triang)
4369                 if (e->invers->next == e
4370                     || e->invers->next->invers->next == e
4371                     || e->invers->next->invers->next->invers->next != e)
4372             {
4373                 fprintf(stderr,">E face error, code=%d\n",code);
4374                 exit(1);
4375             }
4376 
4377             if (e->min != e && e->min != e->invers)
4378             {
4379                 fprintf(stderr,">E min error 1, code=%d\n",code);
4380                 exit(1);
4381             }
4382 
4383 	    if (e->invers->min != e->min)
4384 	    {
4385                 fprintf(stderr,">E min error 2, code=%d\n",code);
4386                 exit(1);
4387             }
4388         }
4389     }
4390 }
4391 
4392 /**************************************************************************/
4393 
4394 static void
got_one(int nbtot,int nbop,int connec)4395 got_one(int nbtot, int nbop, int connec)
4396 
4397 /* This is called when a complete output graph is formed.  The main
4398    purpose is to write the graph and to collect some stats. */
4399 {
4400     int doflip,wt;
4401 #ifdef STATS
4402     int numroot,ii,mind;
4403 #ifdef STATS2
4404     int num2,i;
4405 #endif
4406 #endif
4407 
4408     if (xswitch && connec != xconnec) return;
4409 
4410     doflip = oswitch && (nbop == nbtot || nbop == 0);
4411     wt = doflip ? 2 : 1;
4412 
4413     if (Vswitch)
4414     {
4415 	if (nbtot == 1 || (oswitch && nbop == 1))
4416 	{
4417 	    nout_V += wt;
4418 	    return;
4419 	}
4420     }
4421 
4422 #ifdef FILTER
4423     if (!FILTER(nbtot,nbop,doflip)) return;
4424 #endif
4425 
4426     ++nout[connec];
4427     if (oswitch) nout_op[connec] += wt;
4428 
4429     if (pswitch)
4430     {
4431 	if (oswitch) nout_e_op[ne/2] += wt;
4432 	++nout_e[ne/2];
4433     }
4434 
4435     if (polygonsize == 0)
4436     {
4437 	if (oswitch) nout_p_op[outside_face_size] += wt;
4438 	++nout_p[outside_face_size];
4439     }
4440 
4441 #ifdef STATS
4442     if (polygonsize < 0)
4443     {
4444 	numroot = wt * numedgeorbits(nbtot,nbop);
4445 	numrooted += numroot;
4446 	if (pswitch) numrooted_e[ne/2] += numroot;
4447 	mind = degree[0];
4448 	for (ii = 1; ii < nv; ++ii) if (degree[ii] < mind) mind = degree[ii];
4449         if (degree[nv-1] < 6) nummindeg[mind] += wt;
4450     }
4451     else
4452     {
4453         numroot = wt * numorbitsonface(nbtot,nbop,code_edge);
4454         numrooted += numroot;
4455         numbigface[degree[missing_vertex]] += numroot;
4456     }
4457     if (needgroup && nbtot == 1) ntriv += wt;
4458 #ifdef STATS2
4459     num2 = 0;
4460     for (i = 0; i < nv; ++i) if (degree[i] == 2) ++num2;
4461     numtwos[num2] += wt;
4462 #endif
4463 #endif
4464 
4465 #ifndef SPLITTEST
4466     if (!uswitch)
4467     {
4468 	gotone_nbop = nbop;
4469 	gotone_nbtot = nbtot;
4470         if (dswitch) (*write_dual_graph)(outfile,doflip);
4471         else         (*write_graph)(outfile,doflip);
4472     }
4473 #endif
4474 }
4475 
4476 /**************************************************************************/
4477 
4478 static void
sortedges(EDGE ** ed,int ned)4479 sortedges(EDGE **ed, int ned)
4480 
4481 /* Sort an array of edges according to address.
4482    Good for short arrays only. */
4483 {
4484     register int i,j;
4485     EDGE *edi;
4486 
4487     for (i = 1; i < ned; ++i)
4488     {
4489         edi = ed[i];
4490         for (j = i; ed[j-1] > edi; )
4491         {
4492             ed[j] = ed[j-1];
4493             if (--j <= 0) break;
4494         }
4495         ed[j] = edi;
4496     }
4497 }
4498 
4499 /**************************************************************************/
4500 
4501 static int
isminset(EDGE ** ed,int ned,int nbtot,int nbop,EDGE * old_numbering[][MAXE],EDGE * new_numbering[][MAXE],int * xnbtot,int * xnbop)4502 isminset(EDGE **ed, int ned, int nbtot, int nbop,
4503 	 EDGE *old_numbering[][MAXE], EDGE *new_numbering[][MAXE],
4504 	 int *xnbtot, int *xnbop)
4505 
4506 /* Test if the set ed[0..ned-1] is minimal under the group given by
4507    old_numbering.  These are assumed to be undirected edges matching
4508    their min fields.  If it is, *xnbtot and *xnbop are counts for the
4509    stabiliser.  In the case that the stabiliser is not trivial, it is
4510    placed in new_numbering.
4511    (This represents the group, but not a canonical labelling.) */
4512 {
4513     EDGE **nb,**nbnew;
4514     EDGE *image[MAXE];
4515     register int i,j,jnew;
4516     int instabiliser[2*MAXE];
4517 
4518     *xnbtot = 1;
4519     if (nbop > 0) *xnbop = 1; else *xnbop = 0;
4520 
4521     instabiliser[0] = TRUE;
4522 
4523     nb = (EDGE**)old_numbering[0];
4524     for (i = 0; i < ne; ++i) nb[i]->index = i;
4525 
4526     for (j = 1; j < nbtot; ++j)
4527     {
4528         nb = (EDGE**)old_numbering[j];
4529         for (i = 0; i < ned; ++i) image[i] = nb[ed[i]->index]->min;
4530 
4531         sortedges(image,ned);
4532         for (i = 0; i < ned; ++i) if (image[i] != ed[i]) break;
4533         if (i == ned)
4534         {
4535             if (j < nbop) ++*xnbop;
4536             ++*xnbtot;
4537 	    instabiliser[j] = TRUE;
4538         }
4539         else if (image[i] < ed[i])
4540             return FALSE;
4541 	else
4542 	    instabiliser[j] = FALSE;
4543     }
4544 
4545     if (*xnbtot > 1)
4546     {
4547         jnew = 0;
4548         for (j = 0; j < nbtot; ++j)
4549             if (instabiliser[j])
4550 	    {
4551 	        nb = (EDGE**)old_numbering[j];
4552 	        nbnew = (EDGE**)new_numbering[jnew++];
4553 	        for (i = 0; i < ne; ++i) nbnew[i] = nb[i];
4554 	    }
4555     }
4556 
4557     return TRUE;
4558 }
4559 
4560 /***************************************************************/
4561 
4562 /*
4563 static void
4564 delete_edge(EDGE *e)
4565 
4566 /-* deletes edge e. Assumes that none of the endpoints of e has valency 1.
4567    It assumes that e has a triangle ON THE LEFT. The values of left_facesize
4568    are updated according to this assumption.
4569    Currently unused, so commented out. *-/
4570 {
4571 int newfacesize;
4572 EDGE *run, *end;
4573 
4574     firstedge[e->start] = e->next;
4575     firstedge[e->end] = e->invers->next;
4576 
4577     e->prev->next=e->next;
4578     e->next->prev=e->prev;
4579     (degree[e->start])--;
4580 
4581     e=e->invers;
4582 
4583     e->prev->next=e->next;
4584     e->next->prev=e->prev;
4585     (degree[e->start])--;
4586 
4587     ne -= 2;
4588 
4589     end=run=e->prev->invers;
4590          /-* now the face on the right of e when entering this function
4591             is on the left of run *-/
4592     newfacesize=run->left_facesize+1;
4593 
4594     do { run->left_facesize=newfacesize; run=run->prev->invers;
4595        } while (run != end);
4596 }
4597 */
4598 
4599 /***************************************************************/
4600 
4601 static void
insert_edge_tri(EDGE * e)4602 insert_edge_tri(EDGE *e)
4603 
4604 /* inserts the edge previously deleted -- e may not have been modified in
4605    the meantime and the map must look exactly like it looked before deleting
4606    it. On the left hand side of e there must be a triangle after inserting e */
4607 {
4608     int newfacesize;
4609     EDGE *run;
4610 
4611     ne +=2;
4612 
4613     e->prev->next=e;
4614     e->next->prev=e;
4615     (degree[e->start])++;
4616 
4617     e=e->invers;
4618 
4619     e->prev->next=e;
4620     e->next->prev=e;
4621     (degree[e->start])++;
4622 
4623     run=e->prev->invers;
4624 	/* now the face on the right of e when entering this function is
4625            on the left of run */
4626     newfacesize=e->left_facesize;
4627 
4628     for (run=e->prev->invers; run != e; run=run->prev->invers)
4629         run->left_facesize=newfacesize;
4630 
4631     run=e->next;
4632     run->left_facesize=3;
4633     run->invers->next->left_facesize=3;
4634 }
4635 
4636 /************************************************************************/
4637 
4638 static void
insert_edge_general(EDGE * e)4639 insert_edge_general(EDGE *e)
4640 
4641 /* inserts the edge previously deleted -- e may not have been modified in
4642    the meantime and the map must look exactly like it looked before deleting
4643    it. There is no special face size required on the left hand side of e */
4644 {
4645     int newfacesize;
4646     EDGE *run;
4647 
4648     ne +=2;
4649 
4650     e->prev->next=e;
4651     e->next->prev=e;
4652     (degree[e->start])++;
4653 
4654     e=e->invers;
4655 
4656     e->prev->next=e;
4657     e->next->prev=e;
4658     (degree[e->start])++;
4659 
4660     run=e->prev->invers;
4661         /* now the face on the right of e when entering this function is
4662            on the left of run */
4663     newfacesize=e->left_facesize;
4664 
4665     for (run=e->prev->invers; run != e; run=run->prev->invers)
4666         run->left_facesize=newfacesize;
4667 
4668     e=e->invers; /* back to the old */
4669     run=e->prev->invers;
4670     newfacesize=e->left_facesize;
4671     for (run=e->prev->invers; run != e; run=run->prev->invers)
4672         run->left_facesize=newfacesize;
4673 
4674 }
4675 
4676 /************************************************************************/
4677 
4678 static int
threeconn(EDGE * e)4679 threeconn(EDGE *e)
4680 
4681 /* tests whether the graph obtained by deleting EDGE e is still 3-connected.
4682    The edge e may have been deleted or not, but the values in e must be
4683    as before it was (possibly) deleted. The map must have been 3-connected
4684    before -- so especially there weren't any vertices of degree 2.
4685    degree[] is not assumed correct for the endvertices of e.
4686 
4687    On the left hand side of e there must be a triangle
4688    (e->left_facesize==3) and it is assumed that it is checked before
4689    that the endvertices of e have degree at least 3 after the deletion.
4690 
4691    If there is a 2-cut, e->start and e->end cannot be contained, but they
4692    must be in different components, so v=e->prev->end MUST be contained.
4693    It is checked whether v is contained in a face that shares yet another
4694    vertex with the face formerly on the right hand side of e (the new face
4695    obtained by deleting e).
4696 
4697    Returns 1 if it is 3-connected after deleting e, 0 else.  */
4698 
4699 {
4700     EDGE *run, *start, *end;
4701 
4702     start=e->prev->invers;
4703     if (degree[start->start]==3) return 1;
4704 
4705     RESETMARKS_V;
4706 
4707     /* The endvertices of e need not be marked */
4708     for ( run=e->next, end=e->invers->prev->invers ;
4709           run != end; run=run->invers->next) MARK_V(run->end);
4710 
4711 
4712     end=start->prev->prev; /* stops the running around the vertex before
4713 			      the last face */
4714 
4715 /* The first face and the last face contain also one of the endvertices of e,
4716    so if they also contain marked vertices, then there already was a 2-cut. */
4717 
4718     start=start->next;
4719 
4720     while (start != end)
4721       { run=start->invers;
4722         start=start->next;
4723         for ( ; run != start; run=run->prev->invers)
4724 	    if (ISMARKED_V(run->start)) return 0;
4725       }
4726 
4727     return 1;
4728 }
4729 
4730 /************************************************************************/
4731 
4732 static int
twoconn(EDGE * e)4733 twoconn(EDGE *e)
4734 
4735 /* tests whether the graph obtained by deleting EDGE e is still 2-connected.
4736    The edge e may have been deleted or not, but the values in e must be
4737    as before it was (possibly) deleted. The map must have been 2-connected
4738    before.  degree[] is not assumed correct for the endvertices of e.
4739 
4740    On the left hand side of e there must be a triangle (e->left_facesize==3).
4741 
4742    If there is a 1-cut, it cannot be e->start or e->end (otherwise
4743    it was a 1-cut before), but they must be in different components, (same
4744    reason), so v=e->prev->end MUST be the cutvertex.
4745    It is checked whether v is contained in the face on the right hand side
4746    of e (before deleting).
4747 
4748    Returns 1 if it is 2-connected after deleting e, 0 else.
4749 */
4750 
4751 {
4752     EDGE *run, *end;
4753     int v;
4754 
4755     end = e->next;
4756     if (end == e->prev) return 0;
4757     end = end->invers;
4758 
4759     v = e->prev->end;
4760     if (degree[v] == 2) return 1;
4761 
4762     for (run = e->invers->prev; run != end; run = run->invers->prev)
4763         if (run->end == v) return 0;
4764 
4765    return 1;
4766 }
4767 
4768 /***************************************************************/
4769 
4770 #if 0
4771 static int
4772 edge_del_conn(EDGE *e, int connectivity)
4773 
4774 /* computes the connectivity of the graph after the removal of edge e.
4775    The edge e may have been deleted or not, but the values in e must be
4776    as before it was (possibly) deleted.  degree[] is not assumed correct.
4777    The argument connectivity gives the largest possible value k in {1,2,3}
4778    so that the map is k-connected before the removal of e. Larger values
4779    for the connectivity lead to an error. The value returned is also one
4780    of 1,2,3.
4781 
4782    If connectivity==3 then the endvertices of e are assumed to have
4783    degree>3 before removing e. This must be guaranteed before calling
4784    the function.
4785 
4786    On the left hand side of e there must be a triangle (e->left_facesize==3).
4787 */
4788 
4789 {
4790   if (connectivity==3) return (2+threeconn(e));
4791   if (connectivity==2) return (1+twoconn(e));
4792   return 1;
4793 }
4794 #endif
4795 
4796 /************************************************************************/
4797 
4798 static void
prune_poly_edgelist(EDGE * old[],int numold,EDGE * newe[],int * numnew)4799 prune_poly_edgelist(EDGE *old[], int numold, EDGE *newe[], int *numnew)
4800 
4801 /* Copy from old[0..numold-1] to newe[0..*numnew-1] each edge e with
4802    these two properties:
4803    1. Both ends of e have degree >= minpolydeg+1.
4804    2. e is contained in a 3-face.
4805    It is legal that old and newe and &numold and numnew are the same.
4806 
4807    17Aug2005: Changed "new" to "newe" to avoid Codewarrior bug.
4808 */
4809 
4810 {
4811     int i,counter=0;
4812     EDGE *e;
4813 
4814     for (i=0; i<numold; i++, old++)
4815       { e = *old;
4816         if (degree[e->start] > minpolydeg && degree[e->end] > minpolydeg
4817 	     && (e->left_facesize == 3 || e->invers->left_facesize == 3))
4818             newe[counter++]=e;
4819       }
4820 
4821     *numnew=counter;
4822 }
4823 
4824 /***************************************************************************/
4825 
4826 static void
find_special_loopmakers(EDGE * loops[],int num_loops,EDGE * special_loop_makers[],int * num_spec_loops)4827 find_special_loopmakers(EDGE *loops[], int num_loops,
4828 		        EDGE *special_loop_makers[], int *num_spec_loops)
4829 
4830 /* Finds all those loops so that after switching on one side of it there is
4831    a triangle consisting only of loops and on the other there is a double edge.
4832    The edges are given in min form.
4833 
4834    It is assumed that the map handed to this routine does not contain
4835    vertices of valency smaller than "minimumdegree" and the routine only
4836    returns edges that can be switched without producing some.
4837 
4838    Additionally, if tswitch==0 (no -t) it is checked that the double
4839    edges inside the one of the triangles do not contain a loop on
4840    one side, since this would give a double edge in the dual.
4841 
4842    Or to be exact: They do not contain a loop that is neighbouring both the
4843    double edges.
4844 
4845    Note that "other" double edges can occur in the dual in case minimumdegree<3.
4846 */
4847 
4848 {
4849     int i;
4850     EDGE *run, *test;
4851 
4852     *num_spec_loops=0;
4853 
4854     if (num_loops < 2) return;
4855 
4856     RESETMARKS;
4857     RESETMARKS_V;
4858 
4859     for (i=0; i<num_loops; i++)
4860       { run=loops[i];
4861         MARKLO(run); MARKLO(run->invers);
4862         if (ISMARKED_V(run->start)) /* already another loop started
4863 				                       at the same vertex */
4864           /* To determine a switcher, a pair of loops is necessary.
4865              The switcher is always detected by the second loop of the
4866              pair that is visited */
4867           {
4868 	    if (ISMARKED(run->prev->prev) && (degree[run->prev->end]>minimumdeg)
4869 	        && (run->prev->start != run->prev->end))
4870 	    { test=run->prev->invers;
4871 	      /* the first edge at the top inside the double edge */
4872 	      if (tswitch || (test->next->next->invers != test->prev->prev))
4873 		/* the last test is a bit weird in case degree<4 of the test->start
4874 		   but the result is correct */
4875 		{ special_loop_makers[*num_spec_loops]=run->prev->min;
4876                   (*num_spec_loops)++; }
4877 	    }
4878             if (ISMARKED(run->next->next) && (degree[run->next->end]>minimumdeg)
4879 	        && (run->next->start != run->next->end))
4880 	    { test=run->next->invers;
4881 	       if (tswitch || (test->next->next->invers != test->prev->prev))
4882 	      { special_loop_makers[*num_spec_loops]=run->next->min;
4883                 (*num_spec_loops)++; }
4884 	    }
4885             run=run->invers;
4886 	    if (ISMARKED(run->prev->prev) && (degree[run->prev->end]>minimumdeg)
4887 	        && (run->prev->start != run->prev->end))
4888 	    { test=run->prev->invers;
4889 	      if (tswitch || (test->next->next->invers != test->prev->prev))
4890 		{ special_loop_makers[*num_spec_loops]=run->prev->min;
4891 		(*num_spec_loops)++; }
4892 	    }
4893 	    if (ISMARKED(run->next->next) && (degree[run->next->end]>minimumdeg)
4894 	        && (run->next->start != run->next->end))
4895 	    { test=run->next->invers;
4896 	       if (tswitch || (test->next->next->invers != test->prev->prev))
4897 		 { special_loop_makers[*num_spec_loops]=run->next->min;
4898 		 (*num_spec_loops)++; }
4899 	    }
4900 	  }
4901         else MARK_V(run->start);
4902       }
4903 }
4904 
4905 
4906 /**************************************************************************/
4907 
4908 static void
find_loopmakers(EDGE * doubleedges[],int num_doubleedges,EDGE * possible_loops[],int * number_pos_loops)4909 find_loopmakers(EDGE *doubleedges[], int num_doubleedges,
4910                 EDGE *possible_loops[], int *number_pos_loops)
4911 
4912 /* This routine uses nv>3!!
4913 
4914    Computes the lists of edges that can be switched to give a loop.
4915    For every pair of inverse edges, ONE (the smaller one) is written
4916    to list. The total number of edges is written to *number_pos_loops.
4917 
4918    For the computation of the switchers it is useful to know where the
4919    double edges are.  The list doubleedges[] must be supplied as a
4920    list of all edges contained in multiple edges (one direction
4921    only). "num_doubleedges" is its number;
4922 
4923    Some reasoning about degrees in this functions uses the fact that
4924    so far no loops are present in the graph.
4925 
4926    An edge being contained in a double edge cannot be switched to give a
4927    loop.
4928 */
4929 
4930 {
4931     int i,counter=0;
4932     EDGE *run,*buffer;
4933 
4934 
4935     RESETMARKS;
4936 
4937     if ((num_doubleedges<2) ||
4938 	((minimumdeg>=3) && (num_doubleedges<4))) { *number_pos_loops=0; return; }
4939 
4940     for (i=0; i<num_doubleedges; i++)
4941     {   run=doubleedges[i];
4942         MARKLO(run);
4943         MARKLO(run->invers);
4944     }
4945 
4946 /* Now all the edges contained in doubleedges are marked and we can
4947    start testing. We will first look for edges connecting two sets of
4948    double edges. */
4949 
4950     if (num_doubleedges>=4)
4951     for (i=0; i<num_doubleedges; i++)
4952     {   /* there must be a neighbouring doubleedge */
4953         run= doubleedges[i];
4954         if (ISMARKEDLO(run->next) && (!ISMARKEDHI(run->invers->prev))
4955                     && (run->start == run->invers->prev->prev->end))
4956         {   buffer=run->invers->prev;
4957             MARKHI(buffer);
4958             MARKHI(buffer->invers);
4959             possible_loops[counter]=buffer->min;
4960             counter++;
4961         }
4962         run= run->invers;
4963         if (ISMARKEDLO(run->next) && (!ISMARKEDHI(run->invers->prev))
4964                     && (run->start == run->invers->prev->prev->end))
4965         {   buffer=run->invers->prev;
4966             MARKHI(buffer);  MARKHI(buffer->invers);
4967         possible_loops[counter]=buffer->min;
4968         counter++;
4969         }
4970     }
4971 
4972 /* We will now look for switchers that make degree one vertices. They can
4973    be easily found: they are exactly the edges adjacent to degree 2 vertices.
4974    Note that for n>3 there can never be 2 degree 2 vertices neighbouring each other.
4975 */
4976 
4977     if (minimumdeg==1)
4978       for (i=0;i<nv;i++)
4979 	{
4980 	if (degree[i]==2)
4981 	  {
4982 	    possible_loops[counter]=(firstedge[i])->min; counter++;
4983 	    possible_loops[counter]=(firstedge[i])->next->min; counter++;
4984 	  }
4985 	}
4986 
4987     *number_pos_loops=counter;
4988 }
4989 
4990 /************************************************************************/
4991 
4992 static void
prune_edgelist(EDGE * edge[],int * nedges,int nbtot)4993 prune_edgelist(EDGE *edge[], int *nedges, int nbtot)
4994 
4995 /* Reduce edge[0..*nedges-1] (as undirected edges) according to the group */
4996 
4997 {
4998     int i,oldnum,newnum;
4999     EDGE **nb0,**nb,**nblim;
5000 
5001     if (nbtot == 1) return;
5002 
5003     nb0 = (EDGE**)numbering[0];
5004     nblim = (EDGE**)numbering[nbtot];
5005     for (i = 0; i < ne; ++i) nb0[i]->index = i;
5006 
5007     RESETMARKS;
5008 
5009     oldnum = *nedges;
5010     newnum = 0;
5011     for (i = 0; i < oldnum; ++i)
5012     {
5013         nb = nb0 + edge[i]->index;
5014         if (!ISMARKEDLO(*nb))
5015         {
5016 	    edge[newnum++] = edge[i];
5017             for ( ; nb < nblim; nb += MAXE) MARKLO((*nb)->min);
5018         }
5019     }
5020     *nedges = newnum;
5021 }
5022 
5023 /************************************************************************/
5024 
5025 static void
find_start_loops(EDGE * loop[],int nloops,EDGE * start[],EDGE * start_inv[],int * nstarts)5026 find_start_loops(EDGE *loop[], int nloops, EDGE *start[],
5027                  EDGE *start_inv[], int *nstarts)
5028 
5029 /* loop[0..nloops-1] is a list of all the loops.  A "special" loop is
5030    one with one face bounded by non-loops and the other face bounded
5031    by loops.  loop[nloops-1] is known to be special.  If loop[nloops-1]
5032    does not have the lowest vertex degree of all special loops, return
5033    with *nstarts=0.  Otherwise, list in start[0..*nstarts-1] all the
5034    special loops with lowest vertex degree, and in start_inv[0..*nstarts-1]
5035    their inverses.  The orientations in start[] have a loop in the next
5036    direction.
5037 */
5038 
5039 {
5040     int i,nst,mindeg;
5041     EDGE *e;
5042 
5043     e = loop[nloops-1];
5044     if (e->next->start == e->next->end)
5045     {
5046         start[0] = e;
5047         start_inv[0] = e->invers;
5048     }
5049     else
5050     {
5051 	start[0] = e->invers;
5052 	start_inv[0] = e;
5053     }
5054 
5055     nst = 1;
5056     mindeg = degree[start[0]->end];
5057 
5058     for (i = nloops-1; --i >= 0;)
5059     {
5060         e = loop[i];
5061         if ((e->next->start == e->next->end)
5062                          + (e->prev->start == e->prev->end) == 1)
5063         {
5064             if (degree[e->end] < mindeg)
5065             {
5066                 *nstarts = 0;
5067                 return;
5068             }
5069             else if (degree[e->end] == mindeg)
5070 	    {
5071                 if (e->next->start == e->next->end)
5072 	        {
5073 		    start[nst] = e;
5074 		    start_inv[nst++] = e->invers;
5075 		}
5076                 else
5077                 {
5078 		    start_inv[nst] = e;
5079 		    start[nst++] = e->invers;
5080 		}
5081 	    }
5082         }
5083     }
5084 
5085     *nstarts = nst;
5086 }
5087 
5088 /************************************************************************/
5089 
5090 static void
scanspecialloops(EDGE * loop[],int nloops,int nbtot,int nbop)5091 scanspecialloops(EDGE *loop[], int nloops, int nbtot, int nbop)
5092 
5093 /* The recursive procedure for adding special loops.
5094    As this procedure is entered, nv,ne,degree etc are set for some graph,
5095    and nbtot/nbop are the values returned by canon() for that graph.
5096    loops[0..nloops-1] are all the loops, of which there is at least one.
5097    The loops are all in min form. */
5098 {
5099     register int i;
5100     int xnbtot,xnbop,nloopmakers,ngood;
5101     EDGE *loopmaker[MAXE],*good[(MAXE+1)/2],*good_inv[(MAXE+1)/2];
5102 
5103     got_one(nbtot,nbop,1);
5104 
5105 #ifdef PRE_FILTER_SPECIALLOOP
5106     if (!(PRE_FILTER_SPECIALLOOP)) return;
5107 #endif
5108 
5109     find_special_loopmakers(loop,nloops,loopmaker,&nloopmakers);
5110     if (nloopmakers == 0) return;
5111 
5112     if (nbtot > 1) prune_edgelist(loopmaker,&nloopmakers,nbtot);
5113 
5114     for (i = 0; i < nloopmakers; ++i)
5115     {
5116         switch_edge(loopmaker[i]);
5117 
5118         loop[nloops] = loopmaker[i];
5119         find_start_loops(loop,nloops+1,good,good_inv,&ngood);
5120         if (ngood > 0)
5121         {
5122             if (canon_edge_oriented(good,ngood,1,good_inv,ngood,1,
5123 		                        degree,numbering,&xnbtot,&xnbop))
5124                 scanspecialloops(loop,nloops+1,xnbtot,xnbop);
5125         }
5126 
5127         switch_edge_back(loopmaker[i]);
5128     }
5129 }
5130 
5131 /************************************************************************/
5132 
5133 static void
scanordloops(int nbtot,int nbop,int numdoubles)5134 scanordloops(int nbtot, int nbop, int numdoubles)
5135 
5136 /* The code for adding ordinary loops using a grey code.
5137    As this procedure is entered, nv,ne,degree etc are set for some graph,
5138    and nbtot/nbop are the values returned by canon() for that graph.
5139    numdoubles is the number of undirected edges with a parallel mate.
5140    There are no loops when this is called. */
5141 {
5142     register int i,j;
5143     int xnbtot,xnbop,nloopmakers,nloops;
5144     EDGE *loopmaker[2*MAXN],*loop[2*MAXN],**nb0,**nb1,*e1;
5145     int isloop[2*MAXN],partner[2*MAXN],numpseudo,pj;
5146     long x,xlim,w;
5147 
5148 /*  Meaning of isloop[i]:
5149  *  0 = not a loop, possibly available for switching
5150  *  1 = a pseudo-loop: not a loop but unavailable for switching
5151  *  2 = a real loop, available for unswitching
5152  *  numpseudo = number of pseudo-loops at the moment.
5153  */
5154 
5155     got_one(nbtot,nbop,2 + (numdoubles==0));
5156 
5157     // fprintf(stderr,"Check this part of the code -- changed by me:\n");
5158     if ((numdoubles<2) ||
5159 	((minimumdeg>=3) && (numdoubles<4))) return;
5160 
5161     // was: if (numdoubles < 4) return;
5162 
5163 #ifdef PRE_FILTER_ORDLOOP
5164     if (!(PRE_FILTER_ORDLOOP)) return;
5165 #endif
5166 
5167     find_loopmakers(doubles,numdoubles,loopmaker,&nloopmakers);
5168     if (nloopmakers == 0) return;
5169 
5170     for (i = 0; i < nloopmakers; ++i) isloop[i] = 0;
5171     numpseudo = 0;
5172 
5173 
5174     if (nbtot == 1)    /* Case of trivial group */
5175     {
5176 	for (i = 0; i < nloopmakers; ++i) loopmaker[i]->index = i;
5177 	for (i = 0; i < nloopmakers; ++i)
5178 	{
5179 	    if (degree[loopmaker[i]->start] == 2)
5180 		partner[i] = loopmaker[i]->next->min->index;
5181 	    else if (degree[loopmaker[i]->end] == 2)
5182                 partner[i] = loopmaker[i]->invers->next->min->index;
5183 	    else
5184 		partner[i] = -1;
5185 	}
5186 
5187         xlim = 1 << nloopmakers;
5188         for (x = 1; x < xlim; ++x)
5189         {
5190             for (j = 0, w = x; (w & 1) == 0; ++j, w >>= 1) {}
5191             // if (isloop[j]) switch_edge_back(loopmaker[j]);
5192             // else           switch_edge(loopmaker[j]);
5193             // isloop[j] = !isloop[j];
5194 	    if (isloop[j] == 0)
5195 		if (degree[loopmaker[j]->start] == 1
5196                               || degree[loopmaker[j]->end] == 1)
5197 		{
5198 		    isloop[j] = 1;
5199 		    ++numpseudo;
5200 		}
5201 		else
5202 		{
5203 		    switch_edge(loopmaker[j]);
5204 		    isloop[j] = 2;
5205 		}
5206 	    else if (isloop[j] == 1)
5207 	    {
5208 		--numpseudo;
5209 		isloop[j] = 0;
5210 	    }
5211 	    else  /* isloop[j] = 2 */
5212 	    {
5213 		switch_edge_back(loopmaker[j]);
5214 		isloop[j] = 0;
5215 		pj = partner[j];
5216 		if (pj >= 0 && isloop[pj] == 1)
5217 		{
5218 		    e1 = loopmaker[pj];
5219 		    if (degree[e1->start] > 1 && degree[e1->end] > 1)
5220 		    {
5221 			switch_edge(e1);
5222 			isloop[pj] = 2;
5223 			--numpseudo;
5224 		    }
5225 		}
5226 	    }
5227 
5228 	    if (numpseudo > 0) continue;
5229             for (j = 0; j < nv; ++j) if (degree[j] < minimumdeg) break;
5230             if (j < nv) continue;
5231 
5232             for (i = nloops = 0; i < nloopmakers; ++i)
5233                 if (isloop[i]) loop[nloops++] = loopmaker[i];
5234 
5235 	    if (tswitch)
5236 		scanspecialloops(loop,nloops,1,1);
5237 	    else
5238 	    {
5239                 for (j = 0; j < nloops; ++j)
5240                 {
5241                    if (loop[j]->next->next->next->invers == loop[j]
5242                          || loop[j]->prev->prev->prev->invers == loop[j])
5243                        break;
5244                 }
5245                 if (j == nloops) scanspecialloops(loop,nloops,1,1);
5246 	    }
5247         }
5248         if (isloop[nloopmakers-1] == 2)
5249             switch_edge_back(loopmaker[nloopmakers-1]);
5250     }
5251     else   /* Case of non-trivial group */
5252     {
5253         nb0 = (EDGE**)numbering[0];
5254 	nb1 = (EDGE**)saved_numbering[0];
5255 	for (i = 0; i < nbtot; ++i, nb0 += MAXE, nb1 += MAXE)
5256 	    for (j = 0; j < ne; ++j) nb1[j] = nb0[j];
5257 
5258         sortedges(loopmaker,nloopmakers);
5259 	for (i = 0; i < nloopmakers; ++i) loopmaker[i]->index = i;
5260 	for (i = 0; i < nloopmakers; ++i)
5261 	{
5262 	    if (degree[loopmaker[i]->start] == 2)
5263 		partner[i] = loopmaker[i]->next->min->index;
5264 	    else if (degree[loopmaker[i]->end] == 2)
5265                 partner[i] = loopmaker[i]->invers->next->min->index;
5266 	    else
5267 		partner[i] = -1;
5268 	}
5269 
5270         xlim = 1 << nloopmakers;
5271         for (x = 1; x < xlim; ++x)
5272         {
5273             for (j = 0, w = x; (w & 1) == 0; ++j, w >>= 1) {}
5274             // if (isloop[j]) switch_edge_back(loopmaker[j]);
5275             // else           switch_edge(loopmaker[j]);
5276             // isloop[j] = !isloop[j];
5277             if (isloop[j] == 0)
5278                 if (degree[loopmaker[j]->start] == 1
5279 		       || degree[loopmaker[j]->end] == 1)
5280                 {
5281                     isloop[j] = 1;
5282                     ++numpseudo;
5283                 }
5284                 else
5285                 {
5286                     switch_edge(loopmaker[j]);
5287                     isloop[j] = 2;
5288                 }
5289             else if (isloop[j] == 1)
5290             {
5291                 --numpseudo;
5292                 isloop[j] = 0;
5293             }
5294             else  /* isloop[j] = 2 */
5295             {
5296                 switch_edge_back(loopmaker[j]);
5297                 isloop[j] = 0;
5298 		pj = partner[j];
5299 		if (pj >= 0 && isloop[pj] == 1)
5300 		{
5301 		    e1 = loopmaker[pj];
5302 		    if (degree[e1->start] > 1 && degree[e1->end] > 1)
5303 		    {
5304 			switch_edge(e1);
5305 			isloop[pj] = 2;
5306 			--numpseudo;
5307 		    }
5308 		}
5309             }
5310 
5311 	    if (numpseudo > 0) continue;
5312 
5313             for (i = nloops = 0; i < nloopmakers; ++i)
5314                 if (isloop[i] == 2) loop[nloops++] = loopmaker[i];
5315             if (isminset(loop,nloops,nbtot,nbop,
5316 			 saved_numbering,numbering,&xnbtot,&xnbop))
5317             {
5318                 for (j = 0; j < nv; ++j) if (degree[j] < minimumdeg) break;
5319                 if (j < nv) continue;
5320 
5321 		if (tswitch)
5322 		    scanspecialloops(loop,nloops,xnbtot,xnbop);
5323 		else
5324 		{
5325                     for (j = 0; j < nloops; ++j)
5326                     {
5327                         if (loop[j]->next->next->next->invers == loop[j]
5328                               || loop[j]->prev->prev->prev->invers == loop[j])
5329                             break;
5330                     }
5331                     if (j == nloops) scanspecialloops(loop,nloops,xnbtot,xnbop);
5332 		}
5333             }
5334         }
5335         if (isloop[nloopmakers-1] == 2) switch_edge_back(loopmaker[nloopmakers-1]);
5336     }
5337 }
5338 
5339 /**************************************************************************/
5340 
5341 static void
find_double_makers(EDGE * list[],int * number,EDGE * de_list[])5342 find_double_makers(EDGE *list[], int *number, EDGE *de_list[])
5343 
5344 /* Put into list[] the edges that can be flipped to make a new
5345    doubled edge.  Put in de_list[] an example of an edge which
5346    will be in parallel with it after it is flipped.  Put in
5347    *number the number of such things.  All edges are in min form. */
5348 {
5349     int i,j,num,degneeded;
5350     EDGE *run, *dummy;
5351 
5352     degneeded = (minimumdeg == 3 ? 4 : 3);
5353 
5354     num=0;
5355     for (i=0; i<nv; i++)
5356     if (degree[i]>=degneeded)
5357     {   run = firstedge[i];
5358         for (j=degree[i]; j; j--, run=run->next)
5359             if (run==run->min && degree[run->end]>=degneeded)
5360             {
5361                 if (ISADJ(run->next->end,run->prev->end))
5362                 {   dummy = firstedge[run->next->end];
5363                     while (dummy->end != run->prev->end) dummy = dummy->next;
5364                     list[num] = run;
5365                     de_list[num] = dummy->min;
5366                     num++;
5367                 }
5368             }
5369     }
5370     *number = num;
5371 }
5372 
5373 /**************************************************************************/
5374 
5375 static void
update_double_makers(EDGE * list[],int * number,EDGE * de_list[],EDGE * oldlist[],int oldnumber,EDGE * oldde_list[],EDGE * lastflipped)5376 update_double_makers(EDGE *list[], int *number, EDGE *de_list[],
5377     EDGE *oldlist[], int oldnumber, EDGE *oldde_list[], EDGE *lastflipped)
5378 
5379 /* Add more comments.  All edges in the parameters are in min form. */
5380 {
5381     int a,b,c,d; /* the 4 vertices affected by the last check */
5382     int i, j, counter;
5383     EDGE *run, *dummy;
5384     int degneeded;
5385 
5386     degneeded = (minimumdeg == 3 ? 4 : 3);
5387 
5388     RESETMARKS_V;
5389 
5390     a=lastflipped->start; MARK_V(a);
5391     b=lastflipped->end; MARK_V(b);
5392     c=lastflipped->prev->end; MARK_V(c);
5393     d=lastflipped->next->end; MARK_V(d);
5394 
5395 /* abcd must all be distinct, since with lastflipped before and after the
5396    flipping all edges of K_4 are present, so there would have been a loop
5397    before or after -- but so far there are no loops... */
5398 
5399     counter=0;
5400 
5401     for (i=0; i<oldnumber; i++)
5402       { run=oldlist[i];
5403         if (!(ISMARKED_V(run->start) || ISMARKED_V(run->end)))
5404                         /* in this case it will be checked from abcd */
5405        /* The other thing to check is that the edge to be doubled was not
5406       switched away */
5407             if (lastflipped != oldde_list[i])
5408               { list[counter]=run;
5409                 de_list[counter]=oldde_list[i];
5410                 counter++; }
5411     /* if it was switched away, there is NO other edge that would be
5412        doubled, since this would mean that already the edge switched
5413        away was in a double edge and edges contained in double edges
5414        are never switched away, since they cannot double another
5415        (Jordan Curve Theorem). */
5416       }
5417 
5418 /* Note: It is not possible that some edge not adjacent to abcd can double
5419    lastflipped in its new position and is not yet included in the old list:
5420    Lastflipped was flipped in order to double some edge, so there already
5421    was some edge with these endpoints to double. */
5422 
5423 
5424     if (degree[a]>=degneeded)
5425       { run=firstedge[a];
5426         for (j=degree[a]; j; j--, run=run->next)
5427           if ((degree[run->end]>=degneeded) &&
5428                                  ((run==run->min) || !ISMARKED_V(run->end)))
5429       /* edges inside the set are regarded twice, so only one of the
5430          directions should be worked on, edges leaving the set are
5431          regarded only once */
5432           {
5433               if (ISADJ(run->next->end,run->prev->end))
5434               {   dummy = firstedge[run->next->end];
5435                   while (dummy->end != run->prev->end) dummy = dummy->next;
5436                   list[counter] = run->min;
5437                   de_list[counter] = dummy->min;
5438                   counter++;
5439               }
5440           }
5441       }
5442 
5443     if (degree[b]>=degneeded)
5444       { run=firstedge[b];
5445         for (j=degree[b]; j; j--, run=run->next)
5446           if ((degree[run->end]>=degneeded) &&
5447                           ((run==run->min) || !ISMARKED_V(run->end)))
5448           {
5449               if (ISADJ(run->next->end,run->prev->end))
5450               {   dummy = firstedge[run->next->end];
5451                   while (dummy->end != run->prev->end) dummy = dummy->next;
5452                   list[counter] = run->min;
5453                   de_list[counter] = dummy->min;
5454                   counter++;
5455               }
5456           }
5457       }
5458 
5459     if (degree[c]>=degneeded)
5460       { run=firstedge[c];
5461         for (j=degree[c]; j; j--, run=run->next)
5462           if ((degree[run->end]>=degneeded) &&
5463                           ((run==run->min) || !ISMARKED_V(run->end)))
5464           {
5465               if (ISADJ(run->next->end,run->prev->end))
5466               {   dummy = firstedge[run->next->end];
5467                   while (dummy->end != run->prev->end) dummy = dummy->next;
5468                   list[counter] = run->min;
5469                   de_list[counter] = dummy->min;
5470                   counter++;
5471               }
5472           }
5473       }
5474 
5475     if (degree[d]>=degneeded)
5476       { run=firstedge[d];
5477         for (j=degree[d]; j; j--, run=run->next)
5478           if ((degree[run->end]>=degneeded) &&
5479                           ((run==run->min) || !ISMARKED_V(run->end)))
5480           {
5481               if (ISADJ(run->next->end,run->prev->end))
5482               {   dummy = firstedge[run->next->end];
5483                   while (dummy->end != run->prev->end) dummy = dummy->next;
5484                   list[counter] = run->min;
5485                   de_list[counter] = dummy->min;
5486                   counter++;
5487               }
5488           }
5489       }
5490 
5491     *number=counter;
5492 }
5493 
5494 /************************************************************************/
5495 
5496 static void
find_feasible_flips(EDGE * flip[],EDGE * mate[],int count,int feasible[],int nbtot)5497 find_feasible_flips(EDGE *flip[], EDGE *mate[], int count, int feasible[],
5498                                                         int nbtot)
5499 
5500 /* For i=0..count-1, set feasible[i]=1 if flip[i] is the first in its
5501    edge orbit in flip[0..count-1], and feasible[i]=0 otherwise.
5502    Also set feasible[i]=0 if flip[i] will definitely have a worse
5503    colour than mate[i] after flipping. */
5504 
5505 {
5506     int i;
5507     EDGE **nb0,**nb,**nblim;
5508     int flipside1,flipside2,flipcol;
5509     int mateside1,mateside2,matecol;
5510 
5511     if (nbtot == 1)
5512         for (i = 0; i < count; ++i) feasible[i] = 1;
5513     else
5514     {
5515         nb0 = (EDGE**)numbering[0];
5516         nblim = (EDGE**)numbering[nbtot];
5517         for (i = 0; i < ne; ++i) nb0[i]->index = i;
5518 
5519         RESETMARKS;
5520 
5521         for (i = 0; i < count; ++i)
5522         {
5523             nb = nb0 + flip[i]->index;
5524             if (!ISMARKEDLO(*nb))
5525             {
5526                 feasible[i] = 1;
5527                 for ( ; nb < nblim; nb += MAXE) MARKLO((*nb)->min);
5528             }
5529             else
5530                 feasible[i] = 0;
5531         }
5532     }
5533 
5534     for (i = 0; i < count; ++i)
5535         if (feasible[i])
5536         {
5537             mateside1 = mate[i]->next->end;
5538             mateside2 = mate[i]->prev->end;
5539             flipside1 = flip[i]->start;
5540             flipside2 = flip[i]->end;
5541 
5542             flipcol = degree[flipside1] + degree[flipside2] - 2;
5543             matecol = degree[mateside1] + degree[mateside2];
5544 
5545             if (matecol < flipcol)
5546                 feasible[i] = 0;
5547             else
5548             {
5549                 if (mateside1 == flipside1 || mateside1 == flipside2)
5550                     --matecol;
5551                 if (mateside2 == flipside1 || mateside2 == flipside2)
5552                     --matecol;
5553 
5554                 if (matecol < flipcol) feasible[i] = 0;
5555             }
5556         }
5557 }
5558 
5559 /****************************************************************************/
5560 
5561 static void
make_edge_colours(EDGE * test_edge,EDGE * list[],int numlist,EDGE * good[],int * ngood)5562 make_edge_colours(EDGE *test_edge, EDGE *list[], int numlist,
5563                            EDGE *good[], int *ngood)
5564 
5565 /* list[0..numlist-1] give a list of undirected edges, and
5566    test_edge is another undirected edge (perhaps included).
5567    Both must be in min form.
5568 
5569    Calculate a colour for each orientation of all these edges.
5570    If the least colour of an orientation of test_edge is not the
5571    least of all, return with *ngood == 0.
5572    Otherwise, put those directed edges with the same least colour
5573    in good[0..*ngood-1], with test_edge and/or its inverse first.
5574 
5575    It is guaranteed that the edges selected all have the same starting
5576    and ending degree.
5577 
5578    Note that the definition of colour is used also in find_feasible_flips. */
5579 {
5580     EDGE *e;
5581     int i,num_good;
5582     int d1,d2;
5583     long bestcol,col1,col2;
5584 
5585     col1 = col2 = (long)(degree[test_edge->prev->end]
5586                                 + degree[test_edge->next->end]) << 20;
5587     d1 = degree[test_edge->start];
5588     d2 = degree[test_edge->end];
5589     col1 += (long)d1 + ((long)d2 << 10);
5590     col2 += (long)d2 + ((long)d1 << 10);
5591 
5592     bestcol = col1 < col2 ? col1 : col2;
5593 
5594     num_good = 0;
5595     if (col1 == bestcol) good[num_good++] = test_edge;
5596     if (col2 == bestcol) good[num_good++] = test_edge->invers;
5597 
5598     for (i = numlist; --i >= 0; )
5599     {
5600         e = list[i];
5601         if (e == test_edge) continue;
5602 
5603         col1 = col2 = (long)(degree[e->prev->end]
5604                          + degree[e->next->end]) << 20;
5605         d1 = degree[e->start];
5606         d2 = degree[e->end];
5607         col1 += (long)d1 + ((long)d2 << 10);
5608         col2 += (long)d2 + ((long)d1 << 10);
5609         if (col1 < bestcol || col2 < bestcol)
5610         {
5611             *ngood = 0;
5612             return;
5613         }
5614         if (col1 == bestcol) good[num_good++] = e;
5615         if (col2 == bestcol) good[num_good++] = e->invers;
5616     }
5617 
5618     *ngood = num_good;
5619 }
5620 
5621 /****************************************************************************/
5622 
5623 static void
make_am(void)5624 make_am(void)
5625 
5626 /* Make the adjacency matrix of the graph */
5627 {
5628     int i;
5629     EDGE *e,*ex;
5630     long ami;
5631 
5632     for (i = 0; i < nv; ++i)
5633     {
5634         ami = 0;
5635         e = ex = firstedge[i];
5636         do
5637         {
5638             ami |= BIT(e->end);
5639             e = e->next;
5640         } while (e != ex);
5641         am[i] = ami;
5642     }
5643 }
5644 
5645 /****************************************************************************/
5646 
5647 static void
scandouble(int nbtot,int nbop,int numdoubles,EDGE * oldflip[],EDGE * oldmate[],int oldnflip,EDGE * lastflip)5648 scandouble(int nbtot, int nbop, int numdoubles,
5649           EDGE *oldflip[], EDGE *oldmate[], int oldnflip, EDGE *lastflip)
5650 
5651 /* The main node of the recursion for creating double edges.
5652    As this procedure is entered, nv,ne,degree etc are set for some graph,
5653    and nbtot/nbop are the values returned by canon() for that graph.
5654    numdoubles is the number of undirected edges with a parallel mate.
5655    oldflip and oldnflip are the flips for the parent graph, and lastflip
5656    is what was flipped to make this graph.  The initial call is
5657    distinguished by oldnflip==0.  There are no loops yet. */
5658 {
5659     register int i,j;
5660     int xnbtot,xnbop,nflips,xnumdoubles,ngood;
5661     EDGE *flip[MAXE/2],*mate[MAXE/2],*good[MAXE];
5662     int feasible[MAXE/2];
5663     int a,b,c,d;
5664     long ama,amb,amc,amd;
5665 
5666     if (minconnec == 2) got_one(nbtot,nbop,2+(numdoubles==0));
5667 
5668 #ifdef PRE_FILTER_DOUBLE
5669     if (!(PRE_FILTER_DOUBLE)) return;
5670 #endif
5671 
5672     if (oldnflip == 0)
5673     {
5674         make_am();
5675         find_double_makers(flip,&nflips,mate);
5676     }
5677     else
5678         update_double_makers(flip,&nflips,mate,
5679                                         oldflip,oldnflip,oldmate,lastflip);
5680 
5681     find_feasible_flips(flip,mate,nflips,feasible,nbtot);
5682 
5683     if (minconnec == 1) scanordloops(nbtot,nbop,numdoubles);
5684 
5685     for (i = 0; i < nflips; ++i)
5686     {
5687         if (!feasible[i]) continue;
5688 
5689         a = flip[i]->start;     ama = am[a];
5690         b = flip[i]->end;       amb = am[b];
5691         c = flip[i]->prev->end; amc = am[c];
5692         d = flip[i]->next->end; amd = am[d];
5693         am[a] = ama & ~BIT(b);
5694         am[b] = amb & ~BIT(a);
5695         am[c] = amc | BIT(d);
5696         am[d] = amd | BIT(c);
5697         switch_edge(flip[i]);
5698 
5699         doubles[numdoubles] = flip[i];
5700         for (j = 0; j < numdoubles; ++j) if (doubles[j] == mate[i]) break;
5701         if (j == numdoubles)
5702         {
5703             doubles[numdoubles+1] = mate[i];
5704             xnumdoubles = numdoubles + 2;
5705         }
5706         else
5707             xnumdoubles = numdoubles + 1;
5708 
5709         make_edge_colours(flip[i],doubles,xnumdoubles,good,&ngood);
5710 
5711         if (ngood > 0
5712 	    && canon_edge(good,ngood,degree,numbering,&xnbtot,&xnbop))
5713                 scandouble(xnbtot,xnbop,xnumdoubles,flip,mate,nflips,flip[i]);
5714 
5715         am[a] = ama;
5716         am[b] = amb;
5717         am[c] = amc;
5718         am[d] = amd;
5719         switch_edge_back(flip[i]);
5720     }
5721 }
5722 
5723 /****************************************************************************/
5724 
5725 static int
make_colours(int col[],EDGE * e3)5726 make_colours(int col[], EDGE *e3)
5727 /* Make better colours for maxdeg=3, supposing that expand3() has been
5728    performed at position e3 (though it hasn't been yet).
5729    If the virtual new vertex, nv, is not best, return 0.
5730    Otherwise, return the number of vertices with the same
5731    colour as nv (including itself).  Note that for correct
5732    operation, col[nv-1] must have the smallest value in col[]
5733    and all colours must be positive. */
5734 {
5735     register int i,c,c0,nc;
5736     register EDGE *e;
5737     register int v1,v2,v3;
5738 
5739     v1 = e3->start;
5740     v2 = e3->end;
5741     v3 = e3->next->end;
5742 
5743     c0 =  (1 << ((++degree[v1])&7))
5744         + (1 << ((++degree[v2])&7))
5745         + (1 << ((++degree[v3])&7));
5746 
5747     col[nv] = 2;
5748     nc = 1;
5749 
5750     for (i = nv; --i >= 0;)
5751     {
5752         if (degree[i] != 3)
5753             col[i] = degree[i];
5754         else
5755         {
5756             e = firstedge[i];
5757             c = (1 << (degree[e->end]&7))
5758               + (1 << (degree[e->next->end]&7))
5759               + (1 << (degree[e->next->next->end]&7));
5760             if (c > c0)
5761             {
5762                 --degree[v1];
5763                 --degree[v2];
5764                 --degree[v3];
5765                 return 0;
5766             }
5767             else if (c == c0)
5768             {
5769                 col[i] = 2;
5770                 ++nc;
5771             }
5772             else
5773                 col[i] = 3;
5774         }
5775     }
5776 
5777     --degree[v1];
5778     --degree[v2];
5779     --degree[v3];
5780 
5781     return nc;
5782 }
5783 
5784 /**************************************************************************/
5785 
5786 static int
valid5edge(EDGE * e)5787 valid5edge(EDGE *e)
5788 
5789 /* e is an edge leaving a vertex of degree 5.  This function returns
5790    TRUE if e->end is not adjacent to either e->next->next->end or
5791    e->next->next->next->end, and FALSE otherwise. */
5792 {
5793     register EDGE *e1,*ex;
5794     register int u,v;
5795 
5796     e1 = e->next->next;
5797     u = e1->end;
5798     v = e1->next->end;
5799 
5800     ex = e->invers;
5801     for (e1 = ex->next; e1 != ex; e1 = e1->next)
5802         if (e1->end == u || e1->end == v) return FALSE;
5803 
5804     return TRUE;
5805 }
5806 
5807 /*************************************************************************/
5808 
5809 static void
mark_edge_orbits(EDGE * edge[],int count,int minimal[],int nbtot)5810 mark_edge_orbits(EDGE *edge[], int count, int minimal[], int nbtot)
5811 
5812 /* edge[0..count-1] is a list of edges.  Put minimal[i] = 1 if
5813    edge[i] is the first appearance of its orbit, and  minimal[i] = 0
5814    if not.  Orbits on undirected edges are considered. */
5815 {
5816     int i;
5817     EDGE **nb0,**nb,**nblim;
5818 
5819     if (nbtot == 1)
5820         for (i = 0; i < count; ++i) minimal[i] = 1;
5821     else
5822     {
5823         nb0 = (EDGE**)numbering[0];
5824         nblim = (EDGE**)numbering[nbtot];
5825         for (i = 0; i < ne; ++i) nb0[i]->index = i;
5826 
5827         RESETMARKS;
5828 
5829         for (i = 0; i < count; ++i)
5830         {
5831             nb = nb0 + edge[i]->index;
5832             if (!ISMARKEDLO((*nb)->min))
5833             {
5834                 minimal[i] = 1;
5835                 for ( ; nb < nblim; nb += MAXE) MARKLO((*nb)->min);
5836             }
5837             else
5838                 minimal[i] = 0;
5839         }
5840     }
5841 }
5842 
5843 /*************************************************************************/
5844 
5845 static void
check_am2(int code)5846 check_am2(int code)
5847 /* Just check if am2[][] is valid.  Debug only. */
5848 {
5849     int i,j,d;
5850     EDGE *e,*elast;
5851 
5852     for (i = 0; i < nv; ++i)
5853     {
5854         if (am2[i][i] == 0)
5855 	{
5856             fprintf(stderr,">E am2 error 0, code %d\n",code);
5857             exit(1);
5858         }
5859     }
5860 
5861     for (i = 0; i < nv; ++i)
5862     {
5863 	d = 0;
5864 	for (j = 0; j < nv; ++j) d += (am2[i][j] != 0);
5865 	if (d != degree[i]+1)
5866 	{
5867 	    fprintf(stderr,">E am2 error 1, code %d\n",code);
5868 	    exit(1);
5869 	}
5870     }
5871 
5872     for (i = 0; i < nv; ++i)
5873     {
5874         e = elast = firstedge[i];
5875 	do
5876 	{
5877 	    if (am2[i][e->end] == 0)
5878 	    {
5879                 fprintf(stderr,">E am2 error 2, code %d\n",code);
5880                 exit(1);
5881             }
5882 	    e = e->next;
5883 	} while (e != elast);
5884     }
5885 }
5886 
5887 /*************************************************************************/
5888 
5889 static unsigned long int neighbours_c4[MAXE/2][MAXN];
5890 /* neighbours_c4[e][j] is the set of vertices that share a face with vertex j at the moment
5891    that there are e edges in the graph. */
5892 
5893 static void
init_nb4_triangulation(void)5894 init_nb4_triangulation(void)
5895 /* initializes the datastructure neighbours_c4. This routine may only be called for
5896    triangulations!  Only for triangulations the set of neighbours is equal to the
5897    set of vertices a vertex shares a face with.  In fact it does the same as
5898    make_am applied to the neighbours_c4 array, but seems to be faster. */
5899 {
5900 
5901   int i, j, ne_u;
5902   EDGE *run;
5903   unsigned long int *bitv;
5904   ne_u=ne/2;
5905 
5906   for (i=0; i<nv; i++)
5907     { run=firstedge[i];
5908       bitv=neighbours_c4[ne_u]+i;
5909       *bitv=BIT(run->end);
5910       for (j=degree[i]-1; j; j--) { run=run->next; *bitv |=BIT(run->end); }
5911       }
5912 
5913   return;
5914 }
5915 
5916 static int
test_for_c4(EDGE * rem)5917 test_for_c4(EDGE *rem)
5918 
5919 /* assumes that the graph it is called for is 4-connected and tests whether after
5920    removing the edge rem -- that bounds a triangle in prev-direction (left) --
5921    the graph is still 4-connected. If rem=a->b it is tested whether a vertex in
5922    the boundary of the face on the right of rem shares a face with a vertex
5923    different from a,b that also shares a face with the unique vertex on the
5924    left of rem.
5925 
5926    It is assumed that the value in edge->left_facesize is correct.
5927 
5928    Returns 1 if it will be 4-connected and 0 otherwise.
5929 */
5930 
5931 {
5932 
5933   int j;
5934   EDGE *run;
5935   unsigned long int buf, *nb4;
5936 
5937   nb4=neighbours_c4[ne/2];
5938 
5939   run=rem->next;
5940   j=rem->invers->left_facesize-3;
5941   buf= nb4[rem->prev->end] & ~(BIT(rem->start) | BIT(rem->end));
5942 
5943   if (buf & nb4[run->end]) return 0;
5944 
5945   for ( ; j ; j--)
5946     {  run=run->invers->next;
5947         if (buf & nb4[run->end]) return 0; }
5948 
5949   return 1;
5950 
5951 }
5952 
5953 static void
update_neighbours_c4(EDGE * rem)5954 update_neighbours_c4(EDGE *rem)
5955 
5956 /*
5957    Prepares the array neighbours_c4[ne/2-1] for the deletion of the edge *rem.
5958 
5959    Assumes that the graph it is called for is 4-connected also after removing
5960    the edge rem.
5961    In prev direction of rem there must be a triangle.
5962 
5963    It is assumed that the value in edge->left_facesize is correct.
5964 
5965    It computes the data for neighbours_c4 after the edge has been removed,
5966    but assumes that the edge has not yet been removed.
5967 */
5968 
5969 {
5970 
5971   int j;
5972   EDGE *run;
5973   unsigned long int *nb4_new, face, left_v;
5974 
5975   nb4_new=neighbours_c4[ne/2-1];
5976 
5977   memcpy(nb4_new,neighbours_c4[ne/2],nv*sizeof(unsigned long int));
5978 
5979   run=rem->next;
5980   j=rem->invers->left_facesize-3;
5981   left_v=BIT(rem->prev->end);
5982   face=BIT(run->end);
5983   nb4_new[run->end] |= left_v;
5984 
5985   for ( ; j ; j--)
5986     {  run=run->invers->next; face |= BIT(run->end); nb4_new[run->end] |= left_v;  }
5987   nb4_new[rem->prev->end] |=face;
5988 
5989   return;
5990 }
5991 
5992 /*************************************************************************/
5993 
5994 static int
maybe_delete_c4(EDGE * edel,int oldmaxface,int oldmaxlist0,int oldmaxlist1,int * newmaxface,int * newmaxlist0,int * newmaxlist1,EDGE * good_or[],int * ngood_or,int * ncan_or,EDGE * good_inv[],int * ngood_inv,int * ncan_inv)5995 maybe_delete_c4(EDGE *edel, int oldmaxface, int oldmaxlist0, int oldmaxlist1,
5996                 int *newmaxface,int *newmaxlist0,int *newmaxlist1,
5997                 EDGE *good_or[],int *ngood_or,int *ncan_or,
5998                 EDGE *good_inv[],int *ngood_inv,int *ncan_inv)
5999 
6000 /* Assumes there is a 3-face on the left of *edel, and that *edel can
6001    be deleted while keeping degrees >= minpolydeg.  Also, the new face
6002    created will be a largest face.  oldmaxface is the size of the largest
6003    face so far, and inmaxface[oldmaxlist0..oldmaxlist1-1] are the edges
6004    with a face of maximum size on the left.
6005 
6006    This procedure deletes *edel provided the result is 4-connected, and that
6007    the procedure believes the re-insertion of *edel might be a canonical
6008    edge insertion.  The latter decision is based on four combinatorial
6009    invariates: the three vertex degrees at the ends of *edel and on its left,
6010    and the size of the face to the left of edel->prev.
6011 
6012    In case *edel passes the test and is deleted, the edges which may
6013    represent the re-insertion of *edel and optimise the four-part invariant
6014    mentioned above are put in good_or[0..*ncan_or-1] and
6015    good_inv[0..*ncan_inv-1].  This will include at least one of the edges
6016    edel->prev, edel->invers->next and (if there is also a 3-face on the
6017    right of *edel) edel->next and edel->invers->prev.  Then all other edges
6018    which might possibly represent canonical edge insertions are put in
6019    good_or[*ncan_or..*ngood_or-1] or good_inv[*ncan_inv..*ngood_inv-1].
6020    The *_or edges are those for which the inserted edge will be in the
6021    next direction, and the *_inv edges .. the prev direction.
6022 
6023    In addition, if *edel is deleted, inmaxface[*newmaxlist0..*newmaxlist1-1]
6024    will have all edges with a maximum face on the left (that size being put
6025    into *newmaxface).  This list may overlap
6026    inmaxface[oldmaxlist0..oldmaxlist1-1] if the max face size does not
6027    increase.
6028 
6029    Return values:   0 = ok
6030                     1 = rejected by threeconn()
6031 		    2 = rejected by colour
6032 
6033    This version is for 4-connected only!  maybe_delete_c3() is for 3-conn
6034    and maybe_delete() is the more general version that works for connectivity
6035    1 or more.
6036 */
6037 
6038 {
6039 #define DEGENDC4(ed) (degree[ed->end])
6040 #define REJECTC4 {++degree[v1]; ++degree[v2]; return 2;}
6041 #define ORTESTC4(e) {col = DEGENDC4(e); \
6042  if (col > maxcol) REJECTC4 else if (col == maxcol) good_or[ng_or++] = e;}
6043 #define INVTESTC4(e) {col = DEGENDC4(e); \
6044  if (col > maxcol) REJECTC4 else if (col == maxcol) good_inv[ng_inv++] = e;}
6045 #define ORCOLC4(ed) ((degree[ed->invers->prev->end] << 10) + ed->left_facesize)
6046 #define INVCOLC4(ed) \
6047  ((degree[ed->invers->next->end] << 10) + ed->invers->left_facesize)
6048 
6049     EDGE *e1,*e2,*e3,*e4,*ee;
6050     long col,maxcol;
6051     int k,i,v,ng_or,ng_inv,nc_or,nc_inv;
6052     int maxface,v1,v2,v3,v4,maxdeg,nml1;
6053 
6054 
6055     maxface = *newmaxface = edel->invers->left_facesize + 1;
6056     if (maxface > oldmaxface) oldmaxlist0 = oldmaxlist1;
6057     *newmaxlist0 = oldmaxlist0;
6058 
6059     *ngood_or = *ngood_inv = 0;
6060 
6061  /* Now old edges that will be on a largest face (if *edel is deleted)
6062     are in places oldmaxlist0..oldmaxlist1-1.  New edges will be from
6063     oldmaxlist1 to *newmaxlist1-1, but *newmaxlist1 is not set yet. */
6064 
6065     v1 = edel->start;  v2 = edel->end;
6066     maxdeg = (degree[v1] > degree[v2] ? degree[v1] : degree[v2]) - 1;
6067 
6068     e1 = edel->prev;  v3 = e1->end;
6069     e4 = edel->next; v4 = e4->end;
6070 
6071     if (degree[v3] > maxdeg || degree[v4] > maxdeg) return 2;
6072 
6073 
6074     --degree[v1]; --degree[v2];
6075     e2 = edel->invers->next;
6076     e3 = edel->invers->prev;
6077 
6078     maxcol = nc_or = nc_inv = 0;
6079 
6080     if (degree[v1] == maxdeg)
6081     {
6082         col = DEGENDC4(e1);
6083 	maxcol = col;
6084         good_or[nc_or++] = e1;
6085 
6086         if (maxface == 4)
6087 	{
6088 	    col = DEGENDC4(e4);
6089 	    if (col > maxcol)
6090 	    {
6091 		nc_or = nc_inv = 0;
6092 		good_inv[nc_inv++] = e4;
6093 		maxcol = col;
6094 	    }
6095 	    else if (col == maxcol)
6096 	        good_inv[nc_inv++] = e4;
6097 	}
6098     }
6099 
6100     if (degree[v2] == maxdeg)
6101     {
6102 	col = DEGENDC4(e2);
6103 	if (col > maxcol)
6104   	{
6105 	    nc_or = nc_inv = 0;
6106             good_inv[nc_inv++] = e2;
6107 	    maxcol = col;
6108 	}
6109 	else if (col == maxcol)
6110 	    good_inv[nc_inv++] = e2;
6111 
6112 	if (maxface == 4)
6113 	{
6114             col = DEGENDC4(e3);
6115 	    if (col > maxcol)
6116 	    {
6117 		nc_or = nc_inv = 0;
6118 		good_or[nc_or++] = e3;
6119 		maxcol = col;
6120 	    }
6121 	    else if (col == maxcol)
6122 		good_or[nc_or++] = e3;
6123 	}
6124     }
6125 
6126     ng_or = nc_or;  ng_inv = nc_inv;
6127 
6128     if (maxface > 4)
6129     {
6130 	if (degree[v2] == maxdeg) ORTESTC4(e3);
6131 	if (degree[v1] == maxdeg) INVTESTC4(e4);
6132     }
6133 
6134     if (degree[v3] == maxdeg)
6135     {
6136 	ORTESTC4(e2->invers);
6137 	INVTESTC4(e1->invers);
6138     }
6139 
6140     nml1 = oldmaxlist1;
6141 
6142     v = e3->end;
6143     ee = e3->invers;
6144     for (;;)
6145     {
6146 	inmaxface[nml1++] = ee;
6147 	if (degree[v] > maxdeg)
6148 	{
6149 	    REJECTC4
6150 	}
6151 	else if (degree[v] == maxdeg)
6152 	{
6153 	    INVTESTC4(ee);
6154 	    ee = ee->prev;
6155 	    ORTESTC4(ee);
6156 	}
6157 	else
6158 	    ee = ee->prev;
6159 
6160 	if (v == v4) break;
6161 
6162 	v = ee->end;
6163 	ee = ee->invers;
6164     }
6165 
6166     inmaxface[nml1++] = e2;
6167     inmaxface[nml1++] = e1->invers;
6168     inmaxface[nml1++] = e4;
6169 
6170  /* Now test old edges still on max faces */
6171 
6172     for (i = oldmaxlist0; i < oldmaxlist1; ++i)
6173     {
6174 	ee = inmaxface[i];
6175 	if (degree[ee->start] > maxdeg)
6176 	{
6177 	    REJECTC4
6178 	}
6179 	else if (degree[ee->start] == maxdeg)
6180 	{
6181 	    INVTESTC4(ee);
6182 	    ee = ee->prev;
6183 	    ORTESTC4(ee);
6184 	}
6185     }
6186 
6187     if (!test_for_c4(edel))
6188     {
6189 	++degree[v1];
6190 	++degree[v2];
6191 	return 1;
6192     }
6193 
6194  /* Now we have complete success!  Delete edel! */
6195 
6196     update_neighbours_c4(edel);
6197 
6198     *newmaxlist1 = nml1;
6199     *ngood_or = ng_or;
6200     *ngood_inv = ng_inv;
6201     *ncan_or = nc_or;
6202     *ncan_inv = nc_inv;
6203 
6204     for (i = oldmaxlist1; i < nml1; ++i)
6205 	inmaxface[i]->left_facesize = maxface;
6206 
6207     edel->prev->next = edel->next;
6208     edel->next->prev = edel->prev;
6209     edel = edel->invers;
6210     edel->prev->next = edel->next;
6211     edel->next->prev = edel->prev;
6212     firstedge[v1] = e1;
6213     firstedge[v2] = e2;
6214     ne -= 2;
6215 
6216     if (ng_or + ng_inv == 1) return 0;
6217 
6218     maxcol = 0;
6219     for (i = 0; i < nc_or; ++i)
6220         if (ORCOLC4(good_or[i]) > maxcol) maxcol = ORCOLC4(good_or[i]);
6221     for (i = 0; i < nc_inv; ++i)
6222         if (INVCOLC4(good_inv[i]) > maxcol) maxcol = INVCOLC4(good_inv[i]);
6223 
6224     for (i = 0, k = 0; i < nc_or; ++i)
6225         if (ORCOLC4(good_or[i]) == maxcol) good_or[k++] = good_or[i];
6226     *ncan_or = k;
6227     for (; i < ng_or; ++i)
6228     {
6229 	col = ORCOLC4(good_or[i]);
6230         if (col == maxcol)
6231 	    good_or[k++] = good_or[i];
6232         else if (col > maxcol)
6233         {
6234             insert_edge_tri(edel->invers);
6235             *ngood_or = *ngood_inv = 0;
6236 	    return 2;
6237         }
6238     }
6239     *ngood_or = k;
6240 
6241     for (i = 0, k = 0; i < nc_inv; ++i)
6242         if (INVCOLC4(good_inv[i]) == maxcol) good_inv[k++] = good_inv[i];
6243     *ncan_inv = k;
6244     for (; i < ng_inv; ++i)
6245     {
6246 	col = INVCOLC4(good_inv[i]);
6247         if (col == maxcol)
6248             good_inv[k++] = good_inv[i];
6249         else if (col > maxcol)
6250         {
6251             insert_edge_tri(edel->invers);
6252             *ngood_or = *ngood_inv = 0;
6253 	    return 2;
6254         }
6255     }
6256     *ngood_inv = k;
6257 
6258     return 0;
6259 }
6260 
6261 /*************************************************************************/
6262 
6263 static void
scanpoly_c4(int nbtot,int nbop,EDGE * oldfeas[],int noldfeas,int oldmaxface,int oldmaxlist0,int oldmaxlist1)6264 scanpoly_c4(int nbtot, int nbop, EDGE *oldfeas[], int noldfeas,
6265             int oldmaxface, int oldmaxlist0, int oldmaxlist1)
6266 
6267 /* This is the recursive search procedure for 4-conn polytopes.
6268    oldfeas[0..noldfeas-1] are the edges which can be removed
6269    without violating connectivity.  nbtot/nbop represent the
6270    group, as usual.   oldmaxface is the size of the largest face.
6271    inmaxface[oldmaxlist0..oldmaxlist1-1] lists the edges whose
6272    left face has greatest size (unless that is 3).
6273 
6274    This version is for 4-connected only! scanpoly_c3() is for
6275    3-connected and scanpoly() is the more general version that works
6276    for connectivity 1 or more.
6277 */
6278 
6279 {
6280     EDGE *newfeas[MAXE/2],*good_or[MAXE],*good_inv[MAXE],*e,*esave;
6281     int i,nnewfeas,minimal[MAXE/2],newmaxface;
6282     int code,xnbtot,xnbop;
6283     int ngood_or,ncan_or,ngood_inv,ncan_inv;
6284     int newmaxlist0,newmaxlist1;
6285 
6286     if (ne <= edgebound[1]) got_one(nbtot,nbop,3);
6287     if (ne == edgebound[0]) return;
6288     if (ne - 2*noldfeas > edgebound[1]) return;
6289 
6290 #ifdef PRE_FILTER_POLY
6291     if (!(PRE_FILTER_POLY)) return;
6292 #endif
6293 
6294     mark_edge_orbits(oldfeas,noldfeas,minimal,nbtot);
6295 
6296     for (i = 0; i < noldfeas; ++i)
6297     {
6298         if (!minimal[i]) continue;
6299 
6300         e = oldfeas[i];
6301         if (e->left_facesize != 3) e = e->invers;
6302 	if (e->invers->left_facesize < oldmaxface-1
6303                       || e->invers->left_facesize == maxfacesize)
6304             continue;
6305 
6306         code = maybe_delete_c4(e,oldmaxface,oldmaxlist0,oldmaxlist1,
6307 		               &newmaxface,&newmaxlist0,&newmaxlist1,
6308 		               good_or,&ngood_or,&ncan_or,
6309 		               good_inv,&ngood_inv,&ncan_inv);
6310 
6311         if (code == 0)
6312         {
6313 #ifdef FAST_FILTER_POLY
6314 	    if (FAST_FILTER_POLY)
6315 #endif
6316 	    {
6317 	        if (ngood_or + ngood_inv == 1)
6318 	        {
6319                     esave = oldfeas[i];
6320                     oldfeas[i] = oldfeas[noldfeas-1];
6321                     prune_poly_edgelist(oldfeas,noldfeas-1,newfeas,&nnewfeas);
6322                     oldfeas[i] = esave;
6323                     scanpoly_c4(1,1,newfeas,nnewfeas,
6324                              newmaxface,newmaxlist0,newmaxlist1);
6325                 }
6326                 else if (canon_edge_oriented(good_or,ngood_or,ncan_or,
6327                     		             good_inv,ngood_inv,ncan_inv,
6328                     		             degree,numbering,&xnbtot,&xnbop))
6329                 {
6330 		    esave = oldfeas[i];
6331                     oldfeas[i] = oldfeas[noldfeas-1];
6332                     prune_poly_edgelist(oldfeas,noldfeas-1,newfeas,&nnewfeas);
6333                     oldfeas[i] = esave;
6334                     scanpoly_c4(xnbtot,xnbop,newfeas,nnewfeas,
6335 			     newmaxface,newmaxlist0,newmaxlist1);
6336                 }
6337 	    }
6338             insert_edge_tri(e);
6339         }
6340         else if (code == 1)
6341 	{
6342 	    oldfeas[i] = oldfeas[noldfeas-1];
6343 	    minimal[i] = minimal[noldfeas-1];
6344 	    --i;
6345 	    --noldfeas;
6346 	}
6347     }
6348 }
6349 
6350 /*************************************************************************/
6351 
6352 static int
maybe_delete_c3(EDGE * edel,int oldmaxface,int oldmaxlist0,int oldmaxlist1,int * newmaxface,int * newmaxlist0,int * newmaxlist1,EDGE * good_or[],int * ngood_or,int * ncan_or,EDGE * good_inv[],int * ngood_inv,int * ncan_inv)6353 maybe_delete_c3(EDGE *edel, int oldmaxface, int oldmaxlist0, int oldmaxlist1,
6354                 int *newmaxface,int *newmaxlist0,int *newmaxlist1,
6355                 EDGE *good_or[],int *ngood_or,int *ncan_or,
6356                 EDGE *good_inv[],int *ngood_inv,int *ncan_inv)
6357 
6358 /* Assumes there is a 3-face on the left of *edel, and that *edel can
6359    be deleted while keeping degrees >= 3.  Also, the new face created will
6360    be a largest face.  oldmaxface is the size of the largest face so far,
6361    and inmaxface[oldmaxlist0..oldmaxlist1-1] are the edges with a face of
6362    maximum size on the left.
6363 
6364    This procedure deletes *edel provided the result is 3-connected, and that
6365    the procedure believes the re-insertion of *edel might be a canonical
6366    edge insertion.  The latter decision is based on four combinatorial
6367    invariates: the three vertex degrees at the ends of *edel and on its left,
6368    and the size of the face to the left of edel->prev.
6369 
6370    In case *edel passes the test and is deleted, the edges which may
6371    represent the re-insertion of *edel and optimise the four-part invariant
6372    mentioned above are put in good_or[0..*ncan_or-1] and
6373    good_inv[0..*ncan_inv-1].  This will include at least one of the edges
6374    edel->prev, edel->invers->next and (if there is also a 3-face on the
6375    right of *edel) edel->next and edel->invers->prev.  Then all other edges
6376    which might possibly represent canonical edge insertions are put in
6377    good_or[*ncan_or..*ngood_or-1] or good_inv[*ncan_inv..*ngood_inv-1].
6378    The *_or edges are those for which the inserted edge will be in the
6379    next direction, and the *_inv edges .. the prev direction.
6380 
6381    In addition, if *edel is deleted, inmaxface[*newmaxlist0..*newmaxlist1-1]
6382    will have all edges with a maximum face on the left (that size being put
6383    into *newmaxface).  This list may overlap
6384    inmaxface[oldmaxlist0..oldmaxlist1-1] if the max face size does not
6385    increase.
6386 
6387    Return values:   0 = ok
6388                     1 = rejected by threeconn()
6389 		    2 = rejected by colour
6390 
6391    This version is for 3-connected only!  maybe_delete() is the more
6392    general version that works for connectivity 1 or more.
6393 */
6394 
6395 {
6396 #define DEGENDC3(ed) (degree[ed->end])
6397 #define REJECTC3 {++degree[v1]; ++degree[v2]; return 2;}
6398 #define ORTESTC3(e) {col = DEGENDC3(e); \
6399  if (col > maxcol) REJECTC3 else if (col == maxcol) good_or[ng_or++] = e;}
6400 #define INVTESTC3(e) {col = DEGENDC3(e); \
6401  if (col > maxcol) REJECTC3 else if (col == maxcol) good_inv[ng_inv++] = e;}
6402 #define ORCOLC3(ed) ((degree[ed->invers->prev->end] << 10) + ed->left_facesize)
6403 #define INVCOLC3(ed) \
6404  ((degree[ed->invers->next->end] << 10) + ed->invers->left_facesize)
6405 
6406     EDGE *e1,*e2,*e3,*e4,*ee;
6407     long col,maxcol;
6408     int k,i,v,ng_or,ng_inv,nc_or,nc_inv;
6409     int maxface,v1,v2,v3,v4,maxdeg,nml1;
6410 
6411 
6412     maxface = *newmaxface = edel->invers->left_facesize + 1;
6413     if (maxface > oldmaxface) oldmaxlist0 = oldmaxlist1;
6414     *newmaxlist0 = oldmaxlist0;
6415 
6416     *ngood_or = *ngood_inv = 0;
6417 
6418  /* Now old edges that will be on a largest face (if *edel is deleted)
6419     are in places oldmaxlist0..oldmaxlist1-1.  New edges will be from
6420     oldmaxlist1 to *newmaxlist1-1, but *newmaxlist1 is not set yet. */
6421 
6422     v1 = edel->start;  v2 = edel->end;
6423     maxdeg = (degree[v1] > degree[v2] ? degree[v1] : degree[v2]) - 1;
6424 
6425     e1 = edel->prev;  v3 = e1->end;
6426     e4 = edel->next; v4 = e4->end;
6427 
6428     if (degree[v3] > maxdeg || degree[v4] > maxdeg) return 2;
6429 
6430 
6431     --degree[v1]; --degree[v2];
6432     e2 = edel->invers->next;
6433     e3 = edel->invers->prev;
6434 
6435     maxcol = nc_or = nc_inv = 0;
6436 
6437     if (degree[v1] == maxdeg)
6438     {
6439         col = DEGENDC3(e1);
6440 	maxcol = col;
6441         good_or[nc_or++] = e1;
6442 
6443         if (maxface == 4)
6444 	{
6445 	    col = DEGENDC3(e4);
6446 	    if (col > maxcol)
6447 	    {
6448 		nc_or = nc_inv = 0;
6449 		good_inv[nc_inv++] = e4;
6450 		maxcol = col;
6451 	    }
6452 	    else if (col == maxcol)
6453 	        good_inv[nc_inv++] = e4;
6454 	}
6455     }
6456 
6457     if (degree[v2] == maxdeg)
6458     {
6459 	col = DEGENDC3(e2);
6460 	if (col > maxcol)
6461   	{
6462 	    nc_or = nc_inv = 0;
6463             good_inv[nc_inv++] = e2;
6464 	    maxcol = col;
6465 	}
6466 	else if (col == maxcol)
6467 	    good_inv[nc_inv++] = e2;
6468 
6469 	if (maxface == 4)
6470 	{
6471             col = DEGENDC3(e3);
6472 	    if (col > maxcol)
6473 	    {
6474 		nc_or = nc_inv = 0;
6475 		good_or[nc_or++] = e3;
6476 		maxcol = col;
6477 	    }
6478 	    else if (col == maxcol)
6479 		good_or[nc_or++] = e3;
6480 	}
6481     }
6482 
6483     ng_or = nc_or;  ng_inv = nc_inv;
6484 
6485     if (maxface > 4)
6486     {
6487 	if (degree[v2] == maxdeg) ORTESTC3(e3);
6488 	if (degree[v1] == maxdeg) INVTESTC3(e4);
6489     }
6490 
6491     if (degree[v3] == maxdeg)
6492     {
6493 	ORTESTC3(e2->invers);
6494 	INVTESTC3(e1->invers);
6495     }
6496 
6497     nml1 = oldmaxlist1;
6498 
6499     v = e3->end;
6500     ee = e3->invers;
6501     for (;;)
6502     {
6503 	inmaxface[nml1++] = ee;
6504 	if (degree[v] > maxdeg)
6505 	{
6506 	    REJECTC3
6507 	}
6508 	else if (degree[v] == maxdeg)
6509 	{
6510 	    INVTESTC3(ee);
6511 	    ee = ee->prev;
6512 	    ORTESTC3(ee);
6513 	}
6514 	else
6515 	    ee = ee->prev;
6516 
6517 	if (v == v4) break;
6518 
6519 	v = ee->end;
6520 	ee = ee->invers;
6521     }
6522 
6523     inmaxface[nml1++] = e2;
6524     inmaxface[nml1++] = e1->invers;
6525     inmaxface[nml1++] = e4;
6526 
6527  /* Now test old edges still on max faces */
6528 
6529     for (i = oldmaxlist0; i < oldmaxlist1; ++i)
6530     {
6531 	ee = inmaxface[i];
6532 	if (degree[ee->start] > maxdeg)
6533 	{
6534 	    REJECTC3
6535 	}
6536 	else if (degree[ee->start] == maxdeg)
6537 	{
6538 	    INVTESTC3(ee);
6539 	    ee = ee->prev;
6540 	    ORTESTC3(ee);
6541 	}
6542     }
6543 
6544     if (!threeconn(edel))
6545     {
6546 	++degree[v1];
6547 	++degree[v2];
6548 	return 1;
6549     }
6550 
6551  /* Now we have complete success!  Delete edel! */
6552 
6553     *newmaxlist1 = nml1;
6554     *ngood_or = ng_or;
6555     *ngood_inv = ng_inv;
6556     *ncan_or = nc_or;
6557     *ncan_inv = nc_inv;
6558 
6559     for (i = oldmaxlist1; i < nml1; ++i)
6560 	inmaxface[i]->left_facesize = maxface;
6561 
6562     edel->prev->next = edel->next;
6563     edel->next->prev = edel->prev;
6564     edel = edel->invers;
6565     edel->prev->next = edel->next;
6566     edel->next->prev = edel->prev;
6567     firstedge[v1] = e1;
6568     firstedge[v2] = e2;
6569     ne -= 2;
6570 
6571     if (ng_or + ng_inv == 1) return 0;
6572 
6573     maxcol = 0;
6574     for (i = 0; i < nc_or; ++i)
6575         if (ORCOLC3(good_or[i]) > maxcol) maxcol = ORCOLC3(good_or[i]);
6576     for (i = 0; i < nc_inv; ++i)
6577         if (INVCOLC3(good_inv[i]) > maxcol) maxcol = INVCOLC3(good_inv[i]);
6578 
6579     for (i = 0, k = 0; i < nc_or; ++i)
6580         if (ORCOLC3(good_or[i]) == maxcol) good_or[k++] = good_or[i];
6581     *ncan_or = k;
6582     for (; i < ng_or; ++i)
6583     {
6584 	col = ORCOLC3(good_or[i]);
6585         if (col == maxcol)
6586 	    good_or[k++] = good_or[i];
6587         else if (col > maxcol)
6588         {
6589             insert_edge_tri(edel->invers);
6590             *ngood_or = *ngood_inv = 0;
6591 	    return 2;
6592         }
6593     }
6594     *ngood_or = k;
6595 
6596     for (i = 0, k = 0; i < nc_inv; ++i)
6597         if (INVCOLC3(good_inv[i]) == maxcol) good_inv[k++] = good_inv[i];
6598     *ncan_inv = k;
6599     for (; i < ng_inv; ++i)
6600     {
6601 	col = INVCOLC3(good_inv[i]);
6602         if (col == maxcol)
6603             good_inv[k++] = good_inv[i];
6604         else if (col > maxcol)
6605         {
6606             insert_edge_tri(edel->invers);
6607             *ngood_or = *ngood_inv = 0;
6608 	    return 2;
6609         }
6610     }
6611     *ngood_inv = k;
6612 
6613     return 0;
6614 }
6615 
6616 /*************************************************************************/
6617 
6618 static void
scanpoly_c3(int nbtot,int nbop,EDGE * oldfeas[],int noldfeas,int oldmaxface,int oldmaxlist0,int oldmaxlist1)6619 scanpoly_c3(int nbtot, int nbop, EDGE *oldfeas[], int noldfeas,
6620             int oldmaxface, int oldmaxlist0, int oldmaxlist1)
6621 
6622 /* This is the recursive search procedure for polytopes.
6623    oldfeas[0..noldfeas-1] are the edges which can be removed
6624    without violating connectivity.  nbtot/nbop represent the
6625    group, as usual.   oldmaxface is the size of the largest face.
6626    inmaxface[oldmaxlist0..oldmaxlist1-1] lists the edges whose
6627    left face has greatest size (unless that is 3).
6628 
6629    This version is for 3-connected only!  scanpoly() is the more
6630    general version that works for connectivity 1 or more.
6631 */
6632 
6633 {
6634     EDGE *newfeas[MAXE/2],*good_or[MAXE],*good_inv[MAXE],*e,*esave;
6635     int i,nnewfeas,minimal[MAXE/2],newmaxface;
6636     int code,xnbtot,xnbop;
6637     int ngood_or,ncan_or,ngood_inv,ncan_inv;
6638     int newmaxlist0,newmaxlist1;
6639 
6640     if (ne <= edgebound[1]) got_one(nbtot,nbop,3);
6641     if (ne == edgebound[0]) return;
6642     if (ne - 2*noldfeas > edgebound[1]) return;
6643 
6644 #ifdef PRE_FILTER_POLY
6645     if (!(PRE_FILTER_POLY)) return;
6646 #endif
6647 
6648     mark_edge_orbits(oldfeas,noldfeas,minimal,nbtot);
6649 
6650     for (i = 0; i < noldfeas; ++i)
6651     {
6652         if (!minimal[i]) continue;
6653 
6654         e = oldfeas[i];
6655         if (e->left_facesize != 3) e = e->invers;
6656 	if (e->invers->left_facesize < oldmaxface-1
6657                       || e->invers->left_facesize == maxfacesize)
6658             continue;
6659 
6660         code = maybe_delete_c3(e,oldmaxface,oldmaxlist0,oldmaxlist1,
6661 		               &newmaxface,&newmaxlist0,&newmaxlist1,
6662 		               good_or,&ngood_or,&ncan_or,
6663 		               good_inv,&ngood_inv,&ncan_inv);
6664 
6665         if (code == 0)
6666         {
6667 #ifdef FAST_FILTER_POLY
6668 	    if (FAST_FILTER_POLY)
6669 #endif
6670 	    {
6671 	        if (ngood_or + ngood_inv == 1)
6672 	        {
6673                     esave = oldfeas[i];
6674                     oldfeas[i] = oldfeas[noldfeas-1];
6675                     prune_poly_edgelist(oldfeas,noldfeas-1,newfeas,&nnewfeas);
6676                     oldfeas[i] = esave;
6677                     scanpoly_c3(1,1,newfeas,nnewfeas,
6678                              newmaxface,newmaxlist0,newmaxlist1);
6679                 }
6680                 else if (canon_edge_oriented(good_or,ngood_or,ncan_or,
6681                     		             good_inv,ngood_inv,ncan_inv,
6682                     		             degree,numbering,&xnbtot,&xnbop))
6683                 {
6684 		    esave = oldfeas[i];
6685                     oldfeas[i] = oldfeas[noldfeas-1];
6686                     prune_poly_edgelist(oldfeas,noldfeas-1,newfeas,&nnewfeas);
6687                     oldfeas[i] = esave;
6688                     scanpoly_c3(xnbtot,xnbop,newfeas,nnewfeas,
6689 			     newmaxface,newmaxlist0,newmaxlist1);
6690                 }
6691 	    }
6692             insert_edge_tri(e);
6693         }
6694         else if (code == 1)
6695 	{
6696 	    oldfeas[i] = oldfeas[noldfeas-1];
6697 	    minimal[i] = minimal[noldfeas-1];
6698 	    --i;
6699 	    --noldfeas;
6700 	}
6701     }
6702 }
6703 
6704 /*************************************************************************/
6705 
6706 static int
maybe_delete(EDGE * edel,int oldmaxface,int oldmaxlist0,int oldmaxlist1,int * newmaxface,int * newmaxlist0,int * newmaxlist1,EDGE * good_or[],int * ngood_or,int * ncan_or,EDGE * good_inv[],int * ngood_inv,int * ncan_inv,int * connec)6707 maybe_delete(EDGE *edel, int oldmaxface, int oldmaxlist0, int oldmaxlist1,
6708              int *newmaxface, int *newmaxlist0, int *newmaxlist1,
6709              EDGE *good_or[], int *ngood_or, int *ncan_or,
6710              EDGE *good_inv[], int *ngood_inv, int *ncan_inv, int *connec)
6711 
6712 /* Assumes there is a 3-face on the left of *edel, and that *edel can be
6713    deleted while keeping degrees >= minpolydeg.  Also, the new face created
6714    will be a largest face.  oldmaxface is the size of the largest face so far,
6715    and inmaxface[oldmaxlist0..oldmaxlist1-1] are the edges with a face of
6716    maximum size on the left.  *connec is the current connectivity (or 3,
6717    whichever is smaller).
6718 
6719    This procedure deletes *edel provided the result is at least as connected
6720    as minpolyconnec, and that the procedure believes the re-insertion of *edel
6721    might be a canonical edge insertion.  The latter decision is based on
6722    four combinatorial invariates: the three vertex degrees at the ends of
6723    *edel and on its left, and the size of the face to the left of edel->prev.
6724 
6725    In case *edel passes the test and is deleted, the edges which may
6726    represent the re-insertion of *edel and optimise the four-part invariant
6727    mentioned above are put in good_or[0..*ncan_or-1] and
6728    good_inv[0..*ncan_inv-1].  This will include at least one of the edges
6729    edel->prev, edel->invers->next and (if there is also a 3-face on the
6730    right of *edel) edel->next and edel->invers->prev.  Then all other edges
6731    which might possibly represent canonical edge insertions are put in
6732    good_or[*ncan_or..*ngood_or-1] or good_inv[*ncan_inv..*ngood_inv-1].
6733    The *_or edges are those for which the inserted edge will be in the
6734    next direction, and the *_inv edges .. the prev direction.
6735 
6736    In addition, if *edel is deleted, inmaxface[*newmaxlist0..*newmaxlist1-1]
6737    will have all edges with a maximum face on the left (that size being put
6738    into *newmaxface).  This list may overlap
6739    inmaxface[oldmaxlist0..oldmaxlist1-1] if the max face size does not
6740    increase.
6741 
6742    In the case of value 0, *connec is changed to represent the new
6743    connectivity (or 3, whichever is smaller).
6744 
6745    Return values:   0 = ok
6746                     1 = rejected as connectivity will be too small
6747 		    2 = rejected by colour
6748 */
6749 
6750 {
6751 #define DEGEND(e) (degree[e->end])
6752 #define OROK(e) ISNEQADJ(e->start,e->invers->prev->end)
6753 #define INVOK(e) ISNEQADJ(e->start,e->invers->next->end)
6754 #define REJECT(x) {++degree[v1]; ++degree[v2]; return x;}
6755 #define ORTEST(e) {col = DEGEND(e); if (col > maxcol) \
6756   {if (OROK(e)) REJECT(2)} else if (col==maxcol&&OROK(e)) good_or[ng_or++]=e;}
6757 #define INVTEST(e) {col = DEGEND(e); if (col > maxcol) \
6758   {if (INVOK(e)) REJECT(2)} \
6759    else if (col==maxcol&&INVOK(e)) good_inv[ng_inv++]=e;}
6760 #define ORCOL(e) (((long)degree[e->invers->prev->end] << 10)  \
6761                       + e->left_facesize)
6762 #define INVCOL(e) \
6763  (((long)degree[e->invers->next->end] << 10) + e->invers->left_facesize)
6764 
6765     EDGE *e1,*e2,*e3,*e4,*ee,*ea,*eb;
6766     long col,maxcol,col1,col2;
6767     int k,i,ng_or,ng_inv,nc_or,nc_inv;
6768     int maxface,v1,v2,v3,v4,v5;
6769     int da,db,mindeg,maxdeg,nml1;
6770     int newconnec;
6771 
6772     maxface = *newmaxface = edel->invers->left_facesize + 1;
6773     if (maxface > oldmaxface) oldmaxlist0 = oldmaxlist1;
6774     *newmaxlist0 = oldmaxlist0;
6775 
6776     *ngood_or = *ngood_inv = 0;
6777 
6778  /* Now old edges that will be on a largest face (if *edel is deleted)
6779     are in places oldmaxlist0..oldmaxlist1-1.  New edges will be from
6780     oldmaxlist1 to *newmaxlist1-1, but *newmaxlist1 is not set yet. */
6781 
6782     v1 = edel->start;  v2 = edel->end;
6783 
6784  /* mindeg and maxdeg are the degrees of the ends of edel after deletion */
6785     if (degree[v1] < degree[v2])
6786     {
6787 	mindeg = degree[v1]-1; maxdeg = degree[v2]-1;
6788     }
6789     else
6790     {
6791 	mindeg = degree[v2]-1; maxdeg = degree[v1]-1;
6792     }
6793 
6794     e1 = edel->prev; v3 = e1->end;
6795     e4 = edel->next; v4 = e4->end;
6796     e3 = edel->invers->prev;
6797 
6798    /* The following is an efficiency short-cut, but it is assumed
6799       to have been done below. */
6800 
6801     if (maxface == 4)
6802     {
6803 	if (ISNEQADJ(v3,v4) && (degree[v3] > maxdeg || degree[v4] > maxdeg))
6804 	    return 2;
6805     }
6806     else if (degree[v3] > maxdeg)
6807     {
6808 	if (ISNEQADJ(v3,e3->end) || ISNEQADJ(v3,v4)) return 2;
6809     }
6810 
6811     e2 = edel->invers->next;
6812     --degree[v1];
6813     --degree[v2];
6814 
6815     maxcol = nc_or = nc_inv = 0;
6816 
6817     if (degree[v1] == maxdeg)
6818     {
6819         col = DEGEND(e1);
6820 	maxcol = col;
6821         good_or[nc_or++] = e1;
6822 
6823         if (maxface == 4)
6824 	{
6825 	    col = DEGEND(e4);
6826 	    if (col > maxcol)
6827 	    {
6828 		nc_or = nc_inv = 0;
6829 		good_inv[nc_inv++] = e4;
6830 		maxcol = col;
6831 	    }
6832 	    else if (col == maxcol)
6833 	        good_inv[nc_inv++] = e4;
6834 	}
6835     }
6836 
6837     if (degree[v2] == maxdeg)
6838     {
6839 	col = DEGEND(e2);
6840 	if (col > maxcol)
6841   	{
6842 	    nc_or = nc_inv = 0;
6843             good_inv[nc_inv++] = e2;
6844 	    maxcol = col;
6845 	}
6846 	else if (col == maxcol)
6847 	    good_inv[nc_inv++] = e2;
6848 
6849 	if (maxface == 4)
6850 	{
6851             col = DEGEND(e3);
6852 	    if (col > maxcol)
6853 	    {
6854 		nc_or = nc_inv = 0;
6855 		good_or[nc_or++] = e3;
6856 		maxcol = col;
6857 	    }
6858 	    else if (col == maxcol)
6859 		good_or[nc_or++] = e3;
6860 	}
6861     }
6862 
6863     ng_or = nc_or;  ng_inv = nc_inv;
6864 
6865     if (maxface == 4)
6866     {
6867      /* Recall from above that degree[v3,v4] <= maxdeg */
6868 
6869 	if (ISNEQADJ(v3,v4))
6870 	{
6871 	    col1 = degree[v1];
6872 	    col2 = degree[v2];
6873 
6874 	    if (degree[v3] == maxdeg)
6875 	    {
6876 		if (col1 > maxcol) REJECT(2)
6877 	        else if (col1 == maxcol) good_inv[ng_inv++] = e1->invers;
6878 		if (col2 > maxcol) REJECT(2)
6879 		else if (col2 == maxcol) good_or[ng_or++] = e2->invers;
6880 	    }
6881 
6882 	    if (degree[v4] == maxdeg)
6883 	    {
6884 		if (col1 > maxcol) REJECT(2)
6885 	        else if (col1 == maxcol) good_or[ng_or++] = e4->invers;
6886 		if (col2 > maxcol) REJECT(2)
6887 		else if (col2 == maxcol) good_inv[ng_inv++] = e3->invers;
6888 	    }
6889 	}
6890 
6891         nml1 = oldmaxlist1;
6892         inmaxface[nml1++] = e1->invers;
6893         inmaxface[nml1++] = e2;
6894         inmaxface[nml1++] = e3->invers;
6895         inmaxface[nml1++] = e4;
6896     }
6897     else
6898     {
6899 	v5 = e3->end;
6900 
6901 	/* Recall from above that degree[v3] <= maxdeg */
6902 
6903 	if (ISNEQADJ(v3,v5))
6904 	{
6905 	    if (degree[v5] > maxdeg) REJECT(2);
6906 	    col = degree[v2];
6907 	    if (degree[v3] == maxdeg)
6908 	    {
6909 		if (col > maxcol) REJECT(2)
6910                 else if (col == maxcol) good_or[ng_or++] = e2->invers;
6911 	    }
6912 	    if (degree[v5] == maxdeg)
6913 	    {
6914 		if (col > maxcol) REJECT(2)
6915                 else if (col == maxcol) good_inv[ng_inv++] = e3->invers;
6916             }
6917 	}
6918 	if (ISNEQADJ(v3,v4))
6919 	{
6920 	    if (degree[v4] > maxdeg) REJECT(2);
6921 	    col = degree[v1];
6922 	    if (degree[v3] == maxdeg)
6923             {
6924                 if (col > maxcol) REJECT(2)
6925                 else if (col == maxcol) good_inv[ng_inv++] = e1->invers;
6926             }
6927             if (degree[v4] == maxdeg)
6928             {
6929                 if (col > maxcol) REJECT(2)
6930                 else if (col == maxcol) good_or[ng_or++] = e4->invers;
6931             }
6932 	}
6933 
6934         nml1 = oldmaxlist1;
6935 
6936         ea = e3->invers;
6937 	eb = ea->prev;
6938 	do
6939 	{
6940 	    if (ISNEQADJ(ea->end,eb->end))
6941 	    {
6942 		da = DEGEND(ea);
6943 		db = DEGEND(eb);
6944 		if (da > maxdeg || db > maxdeg) REJECT(2);
6945 		col = degree[ea->start];
6946 		if (da == maxdeg)
6947 		{
6948 		    if (col > maxcol) REJECT(2)
6949 		    else if (col == maxcol) good_or[ng_or++] = ea->invers;
6950 		}
6951 		if (db == maxdeg)
6952 		{
6953 		    if (col > maxcol) REJECT(2)
6954 		    else if (col == maxcol) good_inv[ng_inv++] = eb->invers;
6955 		}
6956 	    }
6957 	    inmaxface[nml1++] = ea;
6958 	    ea = eb->invers;
6959 	    eb = ea->prev;
6960 	} while (ea != e4);
6961 
6962         inmaxface[nml1++] = e2;
6963         inmaxface[nml1++] = e1->invers;
6964         inmaxface[nml1++] = e4;
6965     }
6966 
6967  /* Now test old edges still on max faces */
6968 
6969     for (i = oldmaxlist0; i < oldmaxlist1; ++i)
6970     {
6971 	ee = inmaxface[i];
6972 	if (degree[ee->start] > maxdeg)
6973 	{
6974 	    if (INVOK(ee)) REJECT(2);
6975             ee = ee->prev;
6976             if (OROK(ee)) REJECT(2);
6977 	}
6978 	else if (degree[ee->start] == maxdeg)
6979 	{
6980 	    INVTEST(ee);
6981 	    ee = ee->prev;
6982 	    ORTEST(ee);
6983 	}
6984     }
6985 
6986     if (mindeg < *connec)
6987 	newconnec = mindeg;
6988     else if (*connec == 3)
6989 	newconnec = 2 + threeconn(edel);
6990     else if (*connec == 2)
6991 	newconnec = 1 + twoconn(edel);
6992     else
6993 	newconnec = 1;
6994 
6995     if (newconnec < minpolyconnec) REJECT(1);
6996 
6997  /* Now we have complete success!  Just prune the lists a bit and
6998     complete the deletion of edel. */
6999 
7000     edel->prev->next = edel->next;
7001     edel->next->prev = edel->prev;
7002     ee = edel->invers;
7003     ee->prev->next = ee->next;
7004     ee->next->prev = ee->prev;
7005 
7006     for (i = oldmaxlist1; i < nml1; ++i)
7007 	inmaxface[i]->left_facesize = maxface;
7008 
7009     firstedge[v1] = e1;
7010     firstedge[v2] = e2;
7011     ne -= 2;
7012 
7013     *connec = newconnec;
7014 
7015     *newmaxlist1 = nml1;
7016     *ngood_or = ng_or;
7017     *ngood_inv = ng_inv;
7018     *ncan_or = nc_or;
7019     *ncan_inv = nc_inv;
7020 
7021     if (ng_or + ng_inv == 1) return 0;
7022 
7023     maxcol = 0;
7024     for (i = 0; i < nc_or; ++i)
7025         if (ORCOL(good_or[i]) > maxcol) maxcol = ORCOL(good_or[i]);
7026     for (i = 0; i < nc_inv; ++i)
7027         if (INVCOL(good_inv[i]) > maxcol) maxcol = INVCOL(good_inv[i]);
7028 
7029     for (i = 0, k = 0; i < nc_or; ++i)
7030         if (ORCOL(good_or[i]) == maxcol) good_or[k++] = good_or[i];
7031     *ncan_or = k;
7032     for (; i < ng_or; ++i)
7033     {
7034 	col = ORCOL(good_or[i]);
7035         if (col == maxcol)
7036 	    good_or[k++] = good_or[i];
7037         else if (col > maxcol)
7038         {
7039             insert_edge_tri(edel);
7040             *ngood_or = *ngood_inv = 0;
7041 	    return 2;
7042         }
7043     }
7044     *ngood_or = ng_or = k;
7045 
7046     for (i = 0, k = 0; i < nc_inv; ++i)
7047         if (INVCOL(good_inv[i]) == maxcol) good_inv[k++] = good_inv[i];
7048     *ncan_inv = k;
7049     for (; i < ng_inv; ++i)
7050     {
7051 	col = INVCOL(good_inv[i]);
7052         if (col == maxcol)
7053             good_inv[k++] = good_inv[i];
7054         else if (col > maxcol)
7055         {
7056             insert_edge_tri(edel);
7057             *ngood_or = *ngood_inv = 0;
7058 	    return 2;
7059         }
7060     }
7061     *ngood_inv = ng_inv = k;
7062 
7063     return 0;
7064 }
7065 
7066 /*************************************************************************/
7067 
7068 static void
scanpoly(int nbtot,int nbop,EDGE * oldfeas[],int noldfeas,int oldmaxface,int oldmaxlist0,int oldmaxlist1,int connec)7069 scanpoly(int nbtot, int nbop, EDGE *oldfeas[], int noldfeas,
7070          int oldmaxface, int oldmaxlist0, int oldmaxlist1, int connec)
7071 
7072 /* This is the recursive search procedure for polytopes.
7073    oldfeas[0..noldfeas-1] are the edges which can be removed without
7074    violating the degree bound minpolydeg, with some (but not necessarily
7075    all) missing because they are known to violate the connectivity
7076    bound minpolyconnec.  nbtot/nbop represent the group, as usual.
7077    oldmaxface is the size of the largest face.
7078    inmaxface[oldmaxlist0..oldmaxlist1-1] lists the edges whose
7079    left face has greatest size (unless that is 3).  connec is
7080    the actual connectivity, except that values greater than 3
7081    are given as 3. */
7082 {
7083     EDGE *newfeas[MAXE/2],*good_or[MAXE],*good_inv[MAXE],*e,*esave;
7084     int i,nnewfeas,minimal[MAXE/2],newmaxface;
7085     int code,xnbtot,xnbop;
7086     int ngood_or,ncan_or,ngood_inv,ncan_inv;
7087     int newmaxlist0,newmaxlist1,newconnec;
7088 
7089     if (ne <= edgebound[1]) got_one(nbtot,nbop,connec);
7090     if (ne == edgebound[0]) return;
7091     if (ne - 2*noldfeas > edgebound[1]) return;
7092 
7093 #ifdef PRE_FILTER_POLY
7094     if (!(PRE_FILTER_POLY)) return;
7095 #endif
7096 
7097     mark_edge_orbits(oldfeas,noldfeas,minimal,nbtot);
7098 
7099     for (i = 0; i < noldfeas; ++i)
7100     {
7101         if (!minimal[i]) continue;
7102 
7103         e = oldfeas[i];
7104         if (e->left_facesize != 3) e = e->invers;
7105 	if (e->invers->left_facesize < oldmaxface-1
7106                       || e->invers->left_facesize == maxfacesize)
7107             continue;
7108 
7109 	AMDELEDGE(e->start,e->end);
7110 
7111 	newconnec = connec;
7112         code = maybe_delete(e,oldmaxface,oldmaxlist0,oldmaxlist1,
7113 		            &newmaxface,&newmaxlist0,&newmaxlist1,
7114 		            good_or,&ngood_or,&ncan_or,
7115 		            good_inv,&ngood_inv,&ncan_inv,&newconnec);
7116 
7117         if (code == 0)
7118         {
7119 #ifdef FAST_FILTER_POLY
7120             if (FAST_FILTER_POLY)
7121 #endif
7122             {
7123 	        if (ngood_or + ngood_inv == 1)
7124 	        {
7125                     esave = oldfeas[i];
7126                     oldfeas[i] = oldfeas[noldfeas-1];
7127                     prune_poly_edgelist(oldfeas,noldfeas-1,newfeas,&nnewfeas);
7128                     oldfeas[i] = esave;
7129                     scanpoly(1,1,newfeas,nnewfeas,
7130                              newmaxface,newmaxlist0,newmaxlist1,newconnec);
7131                 }
7132                 else if (canon_edge_oriented(good_or,ngood_or,ncan_or,
7133                     		             good_inv,ngood_inv,ncan_inv,
7134                     		             degree,numbering,&xnbtot,&xnbop))
7135                 {
7136                  /* The following line corrects for the fact that canon*()
7137                     finds each automorphism twice if the maximum degree is
7138                     at most 2.  However, it interferes with -o so is disabled.
7139 
7140 	            if (ne <= 2*nv && maxdegree() <= 2) xnbtot = xnbop;
7141                  */
7142 		    esave = oldfeas[i];
7143                     oldfeas[i] = oldfeas[noldfeas-1];
7144                     prune_poly_edgelist(oldfeas,noldfeas-1,newfeas,&nnewfeas);
7145                     oldfeas[i] = esave;
7146                     scanpoly(xnbtot,xnbop,newfeas,nnewfeas,
7147 			     newmaxface,newmaxlist0,newmaxlist1,newconnec);
7148                 }
7149 	    }
7150             insert_edge_tri(e);
7151         }
7152         else if (code == 1)
7153 	{
7154 	    oldfeas[i] = oldfeas[noldfeas-1];
7155 	    minimal[i] = minimal[noldfeas-1];
7156 	    --i;
7157 	    --noldfeas;
7158 	}
7159 	AMADDEDGE(e->start,e->end);
7160     }
7161 }
7162 
7163 /**************************************************************************/
7164 
7165 static void
startpolyscan(int nbtot,int nbop)7166 startpolyscan(int nbtot, int nbop)
7167 
7168 /* This routine begins the scan for general connected planar graphs formed
7169    by removing edges from triangulations.  The current graph is such a
7170    triangulation, and the group is known (parameters nbtot,nbop).
7171 */
7172 
7173 {
7174     EDGE *feasible[MAXE/2];
7175     EDGE *e,*ex;
7176     EDGE **nb0,**nb1;
7177     int i,j,nfeas;
7178 
7179    /* In the -m5 case, the group must be saved and restored. */
7180 
7181     if (minimumdeg == 5 && nbtot > 1)
7182     {
7183         nb0 = (EDGE**)numbering[0];
7184         nb1 = (EDGE**)saved_numbering[0];
7185         for (i = 0; i < nbtot; ++i, nb0 += MAXE, nb1 += MAXE)
7186             for (j = 0; j < ne; ++j) nb1[j] = nb0[j];
7187     }
7188 
7189     if (minpolyconnec < 3)
7190     {
7191         for (i = 0; i < nv; ++i)
7192         {
7193             for (j = 0; j < nv; ++j) am2[i][j] = 0;
7194             am2[i][i] = 1;
7195         }
7196     }
7197 
7198     nfeas = 0;
7199     for (i = 0; i < nv; ++i)
7200     {
7201         e = ex = firstedge[i];
7202         do
7203         {
7204             if (e == e->min && degree[e->start] > minpolydeg
7205                             && degree[e->end] > minpolydeg)
7206                 feasible[nfeas++] = e;
7207 	    e->left_facesize = 3;
7208 	    am2[e->start][e->end] = 1;
7209             e = e->next;
7210         } while (e != ex);
7211     }
7212 
7213     prune_poly_edgelist(feasible,nfeas,feasible,&nfeas);
7214 
7215     if (minpolyconnec == 3)
7216         scanpoly_c3(nbtot,nbop,feasible,nfeas,3,0,0);
7217     else if (minpolyconnec == 4)
7218     {
7219         init_nb4_triangulation();
7220         scanpoly_c4(nbtot,nbop,feasible,nfeas,3,0,0);
7221     }
7222     else
7223         scanpoly(nbtot,nbop,feasible,nfeas,3,0,0,3);
7224 
7225     if (minimumdeg == 5 && nbtot > 1)
7226     {
7227         nb0 = (EDGE**)saved_numbering[0];
7228         nb1 = (EDGE**)numbering[0];
7229         for (i = 0; i < nbtot; ++i, nb0 += MAXE, nb1 += MAXE)
7230             for (j = 0; j < ne; ++j) nb1[j] = nb0[j];
7231     }
7232 }
7233 
7234 /********************************************************************/
7235 
7236 static int
disk_threeconn(EDGE * e)7237 disk_threeconn(EDGE *e)
7238 
7239 /* Checks whether a triangulation of a disk is 3-connected. This is
7240    the case if and only if there are no chords (except for K3).
7241    The edge e must have the triangulation on the right and the outer
7242    face on the left.
7243    Returns TRUE if 3-connected, FALSE otherwise. */
7244 {
7245     EDGE *run, *run2, *buffer;
7246 
7247     if (nv == 3) return FALSE;   /* K3 has connectivity 2 */
7248 
7249     RESETMARKS_V;
7250 
7251 /* It is correct to do the marking and the running and checking in one
7252    wash, since a chord will be detected when the second of the endpoints
7253    is reached */
7254 
7255     MARK_V(e->start); MARK_V(e->end);
7256 
7257     for (buffer=e->invers, run=buffer->next; run != e;
7258                      buffer=run->invers, run=buffer->next)
7259       { MARK_V(run->end);
7260         for (run2=run->next; run2 != buffer; run2=run2->next)
7261             if (ISMARKED_V(run2->end)) return FALSE;
7262       }
7263 
7264     return TRUE;
7265 }
7266 
7267 /******************************************************************/
7268 
7269 static EDGE*
remove_vertex(int i)7270 remove_vertex(int i)
7271 
7272 /* removes vertex i from the graph and returns an edge with the
7273    new face on the left. Note that afterwards the vertices are
7274    in general no more numbered 0...nv-1, but maybe e.g. 0...nv
7275    with some number in the middle missing.
7276 
7277 */
7278 {
7279     EDGE *run, *end, *buffer;
7280 
7281     nv--;
7282     ne -= 2*degree[i];
7283 
7284     run=end=firstedge[i];
7285 
7286     do {
7287         buffer=run->invers;
7288         buffer->prev->next=buffer->next;
7289         buffer->next->prev=buffer->prev;
7290         (degree[buffer->start])--;
7291         firstedge[buffer->start]=buffer->next;
7292         run=run->next;
7293     } while (run!=end);
7294 
7295     missing_vertex = i;
7296     outside_face_size = degree[i];
7297     return buffer->next;
7298 }
7299 
7300 /******************************************************************/
7301 
7302 static void
insert_vertex(int i)7303 insert_vertex(int i)
7304 
7305 /* inserts the previously removed vertex */
7306 {
7307 
7308     EDGE *run, *end, *buffer;
7309 
7310     nv++;
7311     ne += 2*degree[i];
7312 
7313     run=end=firstedge[i];
7314 
7315     do {
7316         buffer=run->invers;
7317         buffer->prev->next=buffer;
7318         buffer->next->prev=buffer;
7319         (degree[buffer->start])++;
7320         run=run->next;
7321    } while (run!=end);
7322 
7323    missing_vertex = -1;
7324 }
7325 
7326 /**************************************************************************/
7327 
7328 static void
polygon_triang(int nbtot,int nbop)7329 polygon_triang(int nbtot, int nbop)
7330 
7331 /* This routine receives a 3-conn triangulation with one more vertex
7332    than the output size.  It then makes the polygon triangulations by
7333    removing inequivalent vertices of the required degree. */
7334 {
7335     int i,j,j0,j1,k,v,connec;
7336     register EDGE **e,**nb0,**nb1,**nbnew,**nblim;
7337     int newnbtot,newnbop;
7338     int vmark[MAXN];
7339     EDGE *ev;
7340 
7341     for (v = 0; v < nv; ++v)
7342         if (polygonsize <= 0 || degree[v] == polygonsize) vmark[v] = 1;
7343 	else                                              vmark[v] = 0;
7344 
7345     if (minimumdeg == 3 || minconnec == 3)
7346     {
7347         for (v = 0; v < nv; ++v)
7348 	if (degree[v] == 3)
7349 	{
7350 	    ev = firstedge[v];
7351 	    vmark[ev->end] = vmark[ev->next->end] = vmark[ev->prev->end] = 0;
7352 	}
7353     }
7354 
7355     if (nbtot == 1)  /* Case of trivial group */
7356     {
7357 	for (v = 0; v < nv; ++v)
7358 	if (vmark[v])
7359         {
7360 #ifdef PRE_FILTER_DISK
7361 	    if (!PRE_FILTER_DISK(v)) continue;
7362 #endif
7363 
7364 	    code_edge = remove_vertex(v);
7365 
7366 	    connec = 2;
7367 	    if (degree[v] == 3)
7368 		connec = 3;
7369 	    else if (minconnec == 3 || xswitch)
7370                 connec += disk_threeconn(code_edge);
7371 	    if (connec >= minconnec)
7372 	        got_one(1,1,connec);
7373 	    insert_vertex(v);
7374 	    code_edge = NULL;
7375 	}
7376     }
7377     else    /* Case of non-trivial group */
7378     {
7379         nb0 = (EDGE**)numbering[0];
7380         nb1 = (EDGE**)saved_numbering[0];
7381         for (i = 0; i < nbtot; ++i, nb0 += MAXE, nb1 += MAXE)
7382             for (j = 0; j < ne; ++j) nb1[j] = nb0[j];
7383 
7384 	nbnew = (EDGE**)saved_numbering[0];
7385 	nblim = (EDGE**)saved_numbering[nbtot];
7386 	for (k = 0; k < ne; ++k)
7387 	{
7388 	    v = nbnew[k]->start;
7389 	    if (!vmark[v]) continue;
7390 
7391 	    newnbtot = newnbop = 0;
7392 	    for (i = 0, e = nbnew+k; e < nblim; ++i, e += MAXE)
7393 	    {
7394 		vmark[(*e)->start] = 0;
7395 	 	if ((*e)->start == v)
7396 		{
7397         	    nb1 = (EDGE**)saved_numbering[i];
7398 		    nb0 = (EDGE**)numbering[newnbtot];
7399 		    for (j0 = j1 = 0; j1 < ne; ++j1)
7400 			if (nb1[j1]->start != v && nb1[j1]->end != v)
7401 			    nb0[j0++] = nb1[j1];
7402 		    if (i < nbop) ++newnbop;
7403 		    ++newnbtot;
7404 		}
7405 	    }
7406 
7407 #ifdef PRE_FILTER_DISK
7408 	    if (!PRE_FILTER_DISK(v)) continue;
7409 #endif
7410 
7411             code_edge = remove_vertex(v);
7412 
7413             connec = 2;
7414             if (degree[v] == 3 && nv > 3)
7415 		connec = 3;
7416             else if (minconnec == 3 || xswitch)
7417                 connec += disk_threeconn(code_edge);
7418 
7419             if (connec >= minconnec)
7420                 got_one(newnbtot,newnbop,connec);
7421             insert_vertex(v);
7422 	    code_edge = NULL;
7423 	}
7424     }
7425 }
7426 
7427 /**************************************************************************/
7428 
7429 static void
scansimple(int nbtot,int nbop)7430 scansimple(int nbtot, int nbop)
7431 
7432 /* The main node of the recursion for triangulations without double
7433    edges or loops.  As this procedure is entered,
7434    nv,ne,degree etc are set for some graph, and nbtot/nbop are the
7435    values returned by canon() for that graph. */
7436 {
7437     EDGE *ext3[MAXE/3],*ext4[MAXE/2],*ext5[MAXE];
7438     int next3,next4,next5;
7439     EDGE *save_list[4];
7440     register int i;
7441     register EDGE *e1,*e2,**nb,**nblim;
7442     EDGE *e,*ex;
7443     int nc,xnbtot,xnbop,v,needed_deg;
7444     int colour[MAXN];
7445     EDGE *firstedge_save[MAXE];
7446 
7447     if (nv == maxnv)
7448     {
7449         if (pswitch)               startpolyscan(nbtot,nbop);
7450 	else if (polygonsize >= 0) polygon_triang(nbtot,nbop);
7451         else if (minconnec == 3)   got_one(nbtot,nbop,3);
7452         else                       scandouble(nbtot,nbop,0,NULL,NULL,0,NULL);
7453         return;
7454     }
7455 
7456     if (nv == splitlevel)
7457     {
7458 #ifdef SPLITTEST
7459 	++splitcases;
7460 	return;
7461 #endif
7462         if (splitcount-- != 0) return;
7463         splitcount = mod - 1;
7464 
7465         for (i = 0; i < nv; ++i) firstedge_save[i] = firstedge[i];
7466     }
7467 
7468    /* The following could be improved significantly by avoiding
7469       extensions that can't lead to success here. */
7470     if (polygonsize >= 9)
7471     {
7472 	needed_deg = polygonsize + nv - maxnv;
7473 	for (i = 0; i < nv; ++i)
7474 	    if (degree[i] >= needed_deg) break;
7475 	if (i == nv) return;
7476     }
7477 
7478 #ifdef PRE_FILTER_SIMPLE
7479     if (!(PRE_FILTER_SIMPLE)) return;
7480 #endif
7481 
7482 #ifndef FIND_EXTENSIONS_SIMPLE
7483 #define FIND_EXTENSIONS_SIMPLE find_extensions
7484 #endif
7485 
7486     FIND_EXTENSIONS_SIMPLE(nbtot,nbop,ext3,&next3,ext4,&next4,ext5,&next5);
7487 
7488     for (i = 0; i < next3; ++i)
7489     {
7490         nc = make_colours(colour,ext3[i]);
7491         if (nc)
7492         {
7493             extend3(ext3[i]);
7494 #ifdef FAST_FILTER_SIMPLE
7495             if (FAST_FILTER_SIMPLE)
7496 #endif
7497             {
7498                 if (nc == 1 && nv == maxnv && !needgroup)
7499                     got_one(1,1,3);
7500                 else if (canon(colour,numbering,&xnbtot,&xnbop))
7501                     scansimple(xnbtot,xnbop);
7502 	    }
7503             reduce3(ext3[i]);
7504         }
7505     }
7506 
7507     for (i = 0; i < next4; ++i)
7508     {
7509         extend4(ext4[i],save_list);
7510 #ifdef FAST_FILTER_SIMPLE
7511         if (FAST_FILTER_SIMPLE)
7512 #endif
7513         {
7514             if (canon(degree,numbering,&xnbtot,&xnbop))
7515             {
7516                 e = numbering[0][0];
7517                 v = e->next->next->end;
7518                 ex = e->invers;
7519                 for (e = ex->next; e != ex; e = e->next) if (e->end == v) break;
7520 
7521                 e1 = ext4[i]->next->invers;
7522                 if (e != ex) e1 = e1->next;
7523 
7524                 e2 = e1->next->next;
7525                 nblim = (EDGE**)numbering[xnbtot];
7526                 for (nb = (EDGE**)numbering[0]; nb < nblim; nb += MAXE)
7527                     if (*nb == e1 || *nb == e2) break;
7528 
7529                 if (nb < nblim) scansimple(xnbtot,xnbop);
7530             }
7531         }
7532         reduce4(ext4[i],save_list);
7533     }
7534 
7535     for (i = 0; i < next5; ++i)
7536     {
7537         extend5(ext5[i],save_list);
7538 #ifdef FAST_FILTER_SIMPLE
7539         if (FAST_FILTER_SIMPLE)
7540 #endif
7541         {
7542             if (canon(degree,numbering,&xnbtot,&xnbop))
7543             {
7544                 e1 = ext5[i]->next->invers;
7545                 e2 = numbering[0][0];
7546                 if (xnbtot == 1)
7547                 {
7548                     if (!valid5edge(e2))
7549                     {
7550                         if (xnbop == 1)
7551                             if (valid5edge(e2->prev)) e2 = e2->prev;
7552                             else                      e2 = e2->next;
7553                         else
7554                             if (valid5edge(e2->next)) e2 = e2->next;
7555                             else                      e2 = e2->prev;
7556                     }
7557                     if (e2 == e1) scansimple(xnbtot,xnbop);
7558                 }
7559                 else
7560                 {
7561                     for (nb = (EDGE**)numbering[0]; !valid5edge(*nb); ++nb) {}
7562 
7563                     nblim = (EDGE**)numbering[xnbtot];
7564                     for ( ; nb < nblim; nb += MAXE)
7565                         if (*nb == e1) break;
7566 
7567                     if (nb < nblim) scansimple(xnbtot,xnbop);
7568                 }
7569             }
7570 	}
7571         reduce5(ext5[i],save_list);
7572     }
7573 
7574     if (nv == splitlevel)
7575         for (i = 0; i < nv; ++i) firstedge[i] = firstedge_save[i];
7576 }
7577 
7578 /***********************************************************************/
7579 
7580 static void
extend_bip_P(EDGE * ref)7581 extend_bip_P(EDGE *ref)
7582 
7583 /* This routine is the implementation of the P-operation in Batagelj's paper.
7584    It inserts two new vertices -- nv and nv+1. The reference edge ref is
7585    the one starting at the vertex to be split that will (always) become a
7586    valency 4 vertex neighbouring the one in the center.
7587 
7588 
7589        a
7590       / \
7591   ---b---c---e  The edge c-->e is the reference edge
7592       \ /
7593        d
7594 
7595 The operations can only be understood by drawing a picture containing the edge
7596 numbers as initialized in init_P_op().
7597 */
7598 {
7599     EDGE *rp, *rn; /* reference->prev and reference->next */
7600     EDGE *start, *work, *work2;
7601     int buffer;
7602 
7603     start=P_op(nv);
7604     rp=ref->prev; rn=ref->next;
7605 
7606     firstedge[ref->start]=rn; /* just in case ref was "firstedge" */
7607     ref->start=ref->invers->end=nv; ref->next=start+4; ref->prev=start+2;
7608     degree[nv]=degree[nv+1]=4;
7609     firstedge[nv]=start; firstedge[nv+1]=start+1;
7610 
7611 
7612     buffer=rn->end;
7613     degree[buffer]+=2;
7614     work=start+4; work->end=buffer; work->prev=ref;
7615     work2=rn->invers->next;
7616     /*work=start+5;*/ work++;
7617       work->start=buffer; work->next=work2; work2->prev=work;
7618     work2=rn->invers;
7619     /*work=start+6;*/ work++;
7620       work->start=buffer; work->prev=work2; work2->next=work;
7621     /*(start+7)*/ work++; work->end=buffer;
7622 
7623     buffer=rn->start;
7624     /*work=start+8;*/ work++;
7625       work->start=buffer; work->prev=rp; work->next=rn; rn->prev=rp->next=work;
7626     /*(start+9)*/ work++; work->end=buffer;
7627 
7628     buffer=rp->end;
7629     degree[buffer]+=2;
7630     work2=rp->invers->prev;
7631     /*work=start+10;*/ work++;
7632       work->start=buffer; work->next=rp->invers; rp->invers->prev=work;
7633     /*(start+11)*/ work++; work->end=buffer;
7634     work=start+3; work->start=buffer; work->prev=work2; work2->next=work;
7635     /*work=start+2;*/ work--; work->end=buffer; work->next=ref;
7636 
7637     nv += 2;
7638     ne += 12;
7639 }
7640 
7641 /***********************************************************************/
7642 
7643 static void
reduce_bip_P(EDGE * ref)7644 reduce_bip_P(EDGE *ref)
7645 
7646 /* This routine is the implementation of the inverse P-operation in Batagelj's
7647    paper. It removes the two new vertices -- nv and nv+1. The reference edge
7648    ref is c->e and when c and e are removed becomes x->e
7649 
7650         a
7651        / \
7652   x---b---c---e  The edge c-->e is the reference edge
7653        \ /
7654         d
7655 
7656 */
7657 {
7658     EDGE *a, *b, *c, *d;
7659      /* 4 edges forming the square whose inside is removed (except ref) */
7660 
7661     a=ref->invers->next;
7662     b=ref->invers->prev;
7663     c=a->invers->next->next->next->invers;
7664     d=b->invers->prev->prev->prev->invers;
7665 
7666     degree[a->end]-=2;  degree[b->end]-=2;
7667 
7668     ref->start=ref->invers->end=c->start;
7669     firstedge[ref->start]=ref;
7670     ref->next=d; d->prev=ref;
7671     ref->prev=c; c->next=ref;
7672 
7673     a=a->invers; c=c->invers;
7674     a->next=c; c->prev=a; firstedge[a->start]=a;
7675 
7676     b=b->invers; d=d->invers;
7677     b->prev=d; d->next=b; firstedge[b->start]=b;
7678 
7679     nv -= 2;
7680     ne -= 12;
7681 }
7682 
7683 /**************************************************************************/
7684 
7685 static void
bip_P_legal(EDGE * ref,EDGE * good_or[],int * ngood_or,int * ngood_ref,EDGE * good_mir[],int * ngood_mir,int * ngood_mir_ref,EDGE * hint)7686 bip_P_legal(EDGE *ref, EDGE *good_or[], int *ngood_or, int *ngood_ref,
7687           EDGE *good_mir[], int *ngood_mir, int *ngood_mir_ref, EDGE *hint)
7688 
7689 /* The P-operation with reference edge *ref has just been performed.
7690    Make a list in good_or[0..*ngood_or-1] of the reference edges of
7691    legal P-reductions (oriented editions) that might be canonical,
7692    with the first *ngood_ref of those being ref.
7693    Make a list in good_mir[0..*ngood_mir-1] of the
7694    reference edges of legal P-reductions (mirror-image editions) that
7695    might be canonical, with the first *ngood_mir_ref of those being ref.
7696    *ngood_ref and *ngood_mir_ref might each be 0 or 1.  If they are
7697    both 0, nothing else need be correct.
7698    All the edges in good_or[] and good_mir[] must start with the same
7699    vertex degree and end with the same vertex degree (actually, colour
7700    as passed to canon_edge_oriented).
7701    The "type" used in this procedure needs to match the requirements of
7702    find_extensions_bip(), so changing it is dangerous.
7703    If hint!=NULL, it is an edge of the graph that has some chance of
7704    being a better P-reduction than the one just performed.
7705 */
7706 {
7707     int i,j,w,z,ok;
7708     long degend,deg0,deg1,deg2,deg3,deg4,deg5;
7709     long thistype,besttype;
7710     EDGE *e,*e1,*ew,*ewlast;
7711 
7712     degend = degree[ref->end];
7713     deg0 = degend << 21;
7714     deg1 = nv-degree[ref->next->next->invers->next->next->end];
7715     deg2 = degree[ref->next->end];
7716     deg3 = degree[ref->prev->end];
7717     deg4 = degree[ref->invers->prev->prev->end];
7718     deg5 = degree[ref->invers->next->next->end];
7719 
7720     besttype = deg0 + (deg1<<11) + (deg2<<2) + (deg3<<1) + deg4-deg5;
7721     thistype = deg0 + (deg1<<11) + (deg3<<2) + (deg2<<1) + deg5-deg4;
7722     if (besttype > thistype)
7723     {
7724         good_or[0] = ref;
7725         *ngood_or = *ngood_ref = 1;
7726         *ngood_mir = *ngood_mir_ref = 0;
7727     }
7728     else if (besttype == thistype)
7729     {
7730         good_or[0] = good_mir[0] = ref;
7731         *ngood_or = *ngood_ref = 1;
7732         *ngood_mir = *ngood_mir_ref = 1;
7733     }
7734     else
7735     {
7736         good_mir[0] = ref;
7737         *ngood_or = *ngood_ref = 0;
7738         *ngood_mir = *ngood_mir_ref = 1;
7739         besttype = thistype;
7740     }
7741 
7742     if (hint)
7743     {
7744 	e = hint;
7745 	w = e->end;
7746 	e1 = e->next->next;
7747 	if (degree[w] >= degend && degree[e->start] == 4
7748  	          && degree[e->next->end] != 4 && degree[e->prev->end] != 4
7749 		  && degree[e1->end] == 4 && e != ref)
7750 	{
7751             z = e1->invers->next->next->end;
7752 	    ok = (degree[z] == 4);
7753 	    if (!ok)
7754 	    {
7755 		ew = e->invers;
7756 		ewlast = ew->prev;
7757 		for (ew = ew->next->next; ew != ewlast; ew = ew->next)
7758 		    if (ew->end == z) break;
7759 		ok = (ew == ewlast);
7760 	    }
7761 
7762 	    if (ok)
7763 	    {
7764 		deg0 = ((long)degree[w] << 21) + ((long)(nv-degree[z]) << 11);
7765                 deg2 = degree[e->next->end];
7766                 deg3 = degree[e->prev->end];
7767                 deg4 = degree[e->invers->prev->prev->end];
7768                 deg5 = degree[e->invers->next->next->end];
7769 
7770                 thistype = deg0 + (deg2<<2) + (deg3<<1) + deg4-deg5;
7771                 if (thistype > besttype)
7772                 {
7773                     *ngood_ref = *ngood_mir_ref = 0;
7774                     return;
7775                 }
7776 
7777                 thistype = deg0 + (deg3<<2) + (deg2<<1) + deg5-deg4;
7778                 if (thistype > besttype)
7779                 {
7780                     *ngood_ref = *ngood_mir_ref = 0;
7781                     return;
7782                 }
7783 	    }
7784 	}
7785     }
7786 
7787     for (i = 0; i < nv; ++i)
7788     if (degree[i] == 4)
7789     {
7790 	e = firstedge[i];
7791 	j = 0;
7792 	if (degree[e->end] == 4) {e1 = e; ++j;} e=e->next;
7793 	if (degree[e->end] == 4) {e1 = e; ++j;} e=e->next;
7794 	if (degree[e->end] == 4) {e1 = e; ++j;} e=e->next;
7795 	if (degree[e->end] == 4) {e1 = e; ++j;}
7796 	if (j != 1) continue;
7797 
7798 	e = e1->next->next;
7799 
7800 	w = e->end;
7801         if (degree[w] < degend) continue;
7802 	if (e == ref) continue;
7803 	z = e1->invers->next->next->end;
7804 
7805 	if (degree[z] != 4)
7806 	{
7807             ew = e->invers;
7808             ewlast = ew->prev;
7809             for (ew = ew->next->next; ew != ewlast; ew = ew->next)
7810                 if (ew->end == z) break;
7811             if (ew != ewlast) continue;
7812 	}
7813 
7814         deg0 = ((long)degree[w] << 21) + ((long)(nv-degree[z]) << 11);
7815 	deg2 = degree[e->next->end];
7816 	deg3 = degree[e->prev->end];
7817         deg4 = degree[e->invers->prev->prev->end];
7818         deg5 = degree[e->invers->next->next->end];
7819 
7820 	thistype = deg0 + (deg2<<2) + (deg3<<1) + deg4-deg5;
7821 	if (thistype > besttype)
7822         {
7823 	    *ngood_ref = *ngood_mir_ref = 0;
7824 	    return;
7825 	}
7826 	else if (thistype == besttype)
7827 	    good_or[(*ngood_or)++] = e;
7828 
7829         thistype = deg0 + (deg3<<2) + (deg2<<1) + deg5-deg4;
7830         if (thistype > besttype)
7831         {
7832             *ngood_ref = *ngood_mir_ref = 0;
7833             return;
7834         }
7835         else if (thistype == besttype)
7836             good_mir[(*ngood_mir)++] = e;
7837     }
7838 }
7839 
7840 /**************************************************************************/
7841 
7842 static int
is_bip_P(EDGE * e)7843 is_bip_P(EDGE *e)
7844 
7845 /* Return 1 if e is the reference edge of a valid P reduction,
7846    otherwise 0.  It must be that e is an edge of the graph. */
7847 {
7848     int z;
7849     EDGE *e1,*ew,*ewlast;
7850 
7851     if (degree[e->start] != 4 || degree[e->end] == 4) return 0;
7852     if (degree[e->next->end] == 4 || degree[e->prev->end] == 4) return 0;
7853     e1 = e->next->next;
7854     if (degree[e1->end] != 4) return 0;
7855     z = e1->invers->next->next->end;
7856     if (degree[z] == 4) return 1;
7857     ew = e->invers;
7858     ewlast = ew->prev;
7859     for (ew = ew->next->next; ew != ewlast; ew = ew->next)
7860         if (ew->end == z) break;
7861     if (ew != ewlast) return 0;
7862     else              return 1;
7863 }
7864 
7865 /**************************************************************************/
7866 
7867 static EDGE*
has_bip_P(void)7868 has_bip_P(void)
7869 
7870 /* If the graph has a legal P-reduction return an example;
7871    otherwise return NULL. */
7872 {
7873 
7874     int i,j,w,z;
7875     EDGE *e,*e1,*ez,*ezlast;
7876 
7877     for (i = 0; i < nv; ++i)
7878     if (degree[i] == 4)
7879     {
7880 	e = firstedge[i];
7881 	j = 0;
7882 	if (degree[e->end] == 4) {e1 = e; ++j;} e=e->next;
7883 	if (degree[e->end] == 4) {e1 = e; ++j;} e=e->next;
7884 	if (degree[e->end] == 4) {e1 = e; ++j;} e=e->next;
7885 	if (degree[e->end] == 4) {e1 = e; ++j;}
7886 	if (j != 1) continue;
7887 
7888 	e = e1->next->next;
7889 
7890 	w = e->end;
7891 	z = e1->invers->next->next->end;
7892 
7893 	if (degree[z] != 4)
7894 	{
7895             ezlast = ez = firstedge[z];
7896             do
7897             {
7898                 if (ez->end == w) break;
7899                 ez = ez->next;
7900             } while (ez != ezlast);
7901             if (ez->end == w) continue;
7902 	}
7903 
7904 	return e;
7905     }
7906     return NULL;
7907 }
7908 
7909 /**************************************************************************/
7910 
7911 static void
extend_bip_Q(EDGE * ref)7912 extend_bip_Q(EDGE *ref)
7913 
7914 /* This routine is the implementation of the Q-operation in Batagelj's
7915    paper.  It inserts one new vertex -- nv. The reference edge ref is
7916    the one starting at the vertex to be split that will (always) become a
7917    valency 4 vertex in the new graph.
7918 
7919         a
7920    |\  /   reference edge nv->a
7921    | \/nv
7922    | /\
7923    |/  \
7924 
7925 The operations can only be understood by drawing a picture containing the edge
7926 numbers as initialized in init_P_op().
7927 */
7928 {
7929     EDGE *a,*b,*c,*d,*x,*start;
7930     int dummy, dummy2;
7931 
7932     start=Q_op(nv);
7933 
7934     firstedge[nv]=ref;
7935     x=ref->next;
7936     b=ref->prev->invers;
7937     a=b->prev;
7938 
7939     d=x->next->invers;
7940     c=d->next;
7941 
7942     ref->start=ref->invers->end=x->start=x->invers->end=nv;
7943 
7944     ref->prev=start+4;
7945 
7946     c->prev=start+1;
7947     d->next=start+2;
7948     b->prev=start+3;
7949     a->next=start+5;
7950 
7951     dummy=c->start; dummy2=a->start;
7952     (degree[dummy])+=2; (degree[dummy2])+=2;
7953     degree[nv]=4; (degree[b->end])-=2;
7954     start->prev=x; x->next=start; start->end=dummy; start++;
7955     /*1*/ start->next=c; c->prev=start; start->start=dummy; start++;
7956     /*2*/ start->prev=d; d->next=start; start->start=dummy;
7957           start->end=dummy2; start++;
7958     /*3*/ start->next=b; b->prev=start; start->start=dummy2;
7959           start->end=dummy; start++;
7960     /*4*/ start->next=ref; ref->prev=start; start->end=dummy2; start++;
7961     /*5*/ start->prev=a; a->next=start; start->start=dummy2;
7962 
7963     b=b->invers; d=d->invers;
7964 
7965     firstedge[b->start]=b;
7966     b->next=d;
7967     d->prev=b;
7968 
7969 
7970     nv++;
7971     ne+=6;
7972 }
7973 
7974 /***********************************************************************/
7975 
7976 static void
reduce_bip_Q(EDGE * ref)7977 reduce_bip_Q(EDGE *ref)
7978 
7979 /* This routine is the implementation of the inverse Q-operation in
7980    Batagelj's paper. It removes the new vertex nv.
7981 */
7982 {
7983 
7984     EDGE *a,*b,*c,*d,*x;
7985 
7986     x=ref->next;
7987     a=ref->invers->next->invers;
7988     b=a->next->next->next;
7989 
7990     c=x->invers->prev->invers;
7991     d=c->prev->prev->prev;
7992 
7993     firstedge[a->start]=a;
7994     firstedge[c->start]=c;
7995 
7996     ref->start=ref->invers->end=x->start=x->invers->end=b->end;
7997     (degree[b->end])+=2;
7998     (degree[a->start])-=2; (degree[c->start])-=2;
7999 
8000     b->prev=a; a->next=b;
8001     c->prev=d; d->next=c;
8002 
8003     b=b->invers; d=d->invers;
8004 
8005     b->next=ref; ref->prev=b;
8006     d->prev=x; x->next=d;
8007 
8008     nv--;
8009     ne-=6;
8010 }
8011 
8012 /**************************************************************************/
8013 
8014 static void
bip_Q_legal(EDGE * ref,EDGE * good_or[],int * ngood_or,int * ngood_ref,EDGE * good_mir[],int * ngood_mir,int * ngood_mir_ref)8015 bip_Q_legal(EDGE *ref, EDGE *good_or[], int *ngood_or, int *ngood_ref,
8016             EDGE *good_mir[], int *ngood_mir,int *ngood_mir_ref)
8017 
8018 /* The Q-operation with reference edge *ref has just been performed.
8019    Make a list in good_or[0..*ngood_or-1] of the reference edges of
8020    legal Q-reductions (oriented editions) that might be canonical,
8021    with the first *ngood_ref of those being ref.
8022    Make a list in good_mir[0..*ngood_mir-1] of the
8023    reference edges of legal P-reductions (mirror-image editions) that
8024    might be canonical, with the first *ngood_mir_ref of those being
8025    ref->next.
8026    *ngood_ref and *ngood_mir_ref might each be 0 or 1.  If they are
8027    both 0, nothing else need be correct.
8028    All the edges in good_or[] and good_mir[] must start with the same
8029    vertex degree and end with the same vertex degree (actually, colour
8030    as passed to canon_edge_oriented).
8031 */
8032 {
8033     int i,j,w,z1,z2;
8034     long thistype,besttype;
8035     EDGE *e,*e1,*ew,*ewlast;
8036 
8037     besttype = ((long)degree[ref->end]<<10)
8038                + degree[ref->next->end] + degree[ref->prev->end];
8039     good_or[0] = ref;
8040     *ngood_or = *ngood_ref = 1;
8041 
8042     e = ref->next;
8043     thistype = ((long)degree[e->end]<<10)
8044                + degree[e->next->end] + degree[e->prev->end];
8045     if (thistype >= besttype)
8046     {
8047         good_mir[0] = e;
8048 	*ngood_mir = *ngood_mir_ref = 1;
8049     }
8050     else
8051 	*ngood_mir = *ngood_mir_ref = 0;
8052 
8053     if (thistype > besttype)
8054     {
8055 	*ngood_or = *ngood_ref = 0;
8056 	besttype = thistype;
8057     }
8058 
8059     for (i = 0; i < nv; ++i)
8060     if (degree[i] == 4)
8061     {
8062         e = firstedge[i];
8063         e1 = e->next->next;
8064         for (j = 0; j < 4; ++j, e=e->next, e1=e1->next)
8065         {
8066             if (degree[e->prev->end] < 6 || degree[e1->end] < 6) continue;
8067             if (e == ref) continue;
8068             w = e1->invers->prev->prev->end;
8069 
8070 	    z1 = e->end;
8071 	    z2 = e->next->end;
8072             ew = ewlast = firstedge[w];
8073             do
8074             {
8075                 if (ew->end == z1 || ew->end == z2) break;
8076                 ew = ew->next;
8077             } while (ew != ewlast);
8078             if (ew->end == z1 || ew->end == z2) continue;
8079 
8080             thistype = ((long)degree[z1]<<10)
8081 				+ degree[z2] + degree[e->prev->end];
8082             if (thistype > besttype)
8083             {
8084                 *ngood_ref = *ngood_mir_ref = 0;
8085                 return;
8086             }
8087 	    else if (thistype == besttype)
8088                 good_or[(*ngood_or)++] = e;
8089 
8090 	    thistype = ((long)degree[z2]<<10) + degree[z1] + degree[e1->end];
8091             if (thistype > besttype)
8092             {
8093                 *ngood_ref = *ngood_mir_ref = 0;
8094                 return;
8095             }
8096             else if (thistype == besttype)
8097                 good_mir[(*ngood_mir)++] = e->next;
8098         }
8099     }
8100 }
8101 
8102 /**************************************************************************/
8103 
8104 static void
find_extensions_bip(int nbtot,int nbop,EDGE * extP[],int * nextP,EDGE * extQ[],int * nextQ,EDGE * Pedges[],int nPedges)8105 find_extensions_bip(int nbtot, int nbop, EDGE *extP[], int *nextP,
8106     EDGE *extQ[], int *nextQ, EDGE *Pedges[], int nPedges)
8107 
8108 /* nbtot and nbop are the usual group parameters.
8109    Place in extP{0..nextP-1] the reference edges of possible P_ops, and
8110    place in extQ{0..nextQ-1] the reference edges of possible Q_ops.
8111    In both cases, only inequivalent edges are listed.
8112 */
8113 {
8114     int Ptot,Qtot;
8115     EDGE *e,*elast,*ev,*evlast,*ee;
8116     EDGE **nb,**nb0,**nblim,**nboplim;
8117     register int i,v,w;
8118     int weight[MAXN],minweight;
8119     int oldPwt,Pv1,Pv2;
8120 
8121     Ptot = Qtot = 0;
8122     for (i = 0; i < nv; ++i) weight[i] = 0;
8123     minweight = 0;
8124     RESETMARKS;
8125     for (i = 0; i < nPedges; ++i)
8126     if (i == nPedges-1 || is_bip_P(Pedges[i]))
8127     {
8128 	e = Pedges[i];
8129 	if (ISMARKEDLO(e)) continue;
8130 	MARKLO(e);
8131 	++weight[e->start];
8132 	e = e->next->next->invers->next->next;
8133 	++weight[e->start]; ++weight[e->end];
8134 	while (degree[e->end] == 4) e = e->invers->next->next;
8135 	MARKLO(e);
8136 	++weight[e->start];
8137 	e = e->prev->prev->invers->prev->prev;
8138 	++weight[e->start]; ++weight[e->end];
8139 	minweight += 2;
8140     }
8141 
8142     if (nv == maxnv-1)
8143     {
8144         if (nbtot == 1)  /* Case of trivial group */
8145         {
8146             for (i = 0; i < nv; ++i)
8147 	    if (degree[i] != 4)
8148 	    {
8149 	        e = elast = firstedge[i];
8150 	        do
8151 	        {
8152 		    v = e->prev->end;
8153                     w = e->next->next->end;
8154 		    if (weight[v]+weight[w] >= minweight)
8155    		    {
8156 			ev = evlast = e->prev->invers;
8157                         for (ev = ev->next; ev != evlast; ev = ev->next)
8158                             if (ev->end == w) break;
8159                         if (ev == evlast) extQ[Qtot++] = e;
8160     		    }
8161 		    e = e->next;
8162 	        } while (e != elast);
8163 	    }
8164         }
8165         else             /* Case of nontrivial group */
8166         {
8167             nb0 = (EDGE**)numbering[0];
8168             nblim = (EDGE**)numbering[nbtot];
8169 	    nboplim = (EDGE**)numbering[nbop==0?nbtot:nbop];
8170             RESETMARKS;
8171             for (i = 0; i < ne; ++i, ++nb0)
8172             {
8173 	        e = *nb0;
8174                 if (!ISMARKEDLO(e) && degree[e->start] >= 6)
8175                 {
8176 		    v = e->prev->end;
8177                     w = e->next->next->end;
8178 
8179 		    if (weight[v]+weight[w] >= minweight)
8180                     {
8181                         ev = evlast = e->prev->invers;
8182                         for (ev = ev->next; ev != evlast; ev = ev->next)
8183                             if (ev->end == w) break;
8184                         if (ev == evlast) extQ[Qtot++] = e;
8185 		    }
8186 
8187 		    nb = nb0 + MAXE;
8188                     for (; nb < nboplim; nb += MAXE) MARKLO(*nb);
8189                     for (; nb < nblim; nb += MAXE) MARKLO((*nb)->prev);
8190                 }
8191             }
8192         }
8193     }
8194     else  /* nv <= maxnv-2 */
8195     {
8196         if (nPedges > 0)
8197 	{
8198 	    e = Pedges[nPedges-1];
8199 	    oldPwt = degree[e->end];
8200 	    Pv1 = e->start;
8201 	    Pv2 = e->next->next->end;
8202 	}
8203 	else
8204 	    oldPwt = 0;
8205 
8206 
8207         if (nbtot == 1)  /* Case of trivial group */
8208         {
8209             for (i = 0; i < nv; ++i)
8210 	    if (degree[i] != 4)
8211 	    {
8212 	        e = elast = firstedge[i];
8213 	        do
8214 	        {
8215 		    if (degree[i] >= oldPwt ||
8216 		        e->next->end == Pv1 || e->next->end == Pv2 ||
8217 			e->prev->end == Pv1 || e->prev->end == Pv2)
8218 		    {
8219 		        for (ee = e; degree[ee->end] == 4;
8220 				         ee = ee->invers->next->next)
8221 		        {}
8222 		        if (degree[i] >= degree[ee->end])
8223 		            extP[Ptot++] = e->invers;
8224 		    }
8225 
8226 		    v = e->prev->end;
8227                     w = e->next->next->end;
8228 
8229 		    if (weight[v]+weight[w] >= minweight)
8230 		    {
8231                         ev = evlast = e->prev->invers;
8232                         for (ev = ev->next; ev != evlast; ev = ev->next)
8233                             if (ev->end == w) break;
8234                         if (ev == evlast) extQ[Qtot++] = e;
8235 		    }
8236 
8237 		    e = e->next;
8238 	        } while (e != elast);
8239 	    }
8240         }
8241         else             /* Case of nontrivial group */
8242         {
8243             nb0 = (EDGE**)numbering[0];
8244             nblim = (EDGE**)numbering[nbtot];
8245             RESETMARKS;
8246 	    for (i = 0; i < ne; ++i, ++nb0)
8247 	    {
8248 	        if (!ISMARKEDLO(*nb0) && degree[(*nb0)->start] >= 6)
8249 	        {
8250 		    e = *nb0;
8251                     if (degree[e->start] >= oldPwt ||
8252                                 e->next->end == Pv1 || e->next->end == Pv2 ||
8253                                 e->prev->end == Pv1 || e->prev->end == Pv2)
8254 		    {
8255                         for (ee = e; degree[ee->end] == 4;
8256 				        ee = ee->invers->next->next)
8257                         {}
8258                         if (degree[e->start] >= degree[ee->end])
8259                             extP[Ptot++] = e->invers;
8260 		    }
8261 
8262 		    for (nb = nb0; nb < nblim; nb += MAXE) MARKLO(*nb);
8263                 }
8264 	    }
8265 
8266 	    nb0 = (EDGE**)numbering[0];
8267 	    nboplim = (EDGE**)numbering[nbop==0?nbtot:nbop];
8268             RESETMARKS;
8269             for (i = 0; i < ne; ++i, ++nb0)
8270             {
8271 	        e = *nb0;
8272                 if (!ISMARKEDLO(e) && degree[e->start] >= 6)
8273                 {
8274 		    v = e->prev->end;
8275                     w = e->next->next->end;
8276 
8277 		    if (weight[v]+weight[w] >= minweight)
8278 		    {
8279                         ev = evlast = e->prev->invers;
8280                         for (ev = ev->next; ev != evlast; ev = ev->next)
8281                             if (ev->end == w) break;
8282                         if (ev == evlast) extQ[Qtot++] = e;
8283 		    }
8284 
8285 		    nb = nb0 + MAXE;
8286                     for (; nb < nboplim; nb += MAXE) MARKLO(*nb);
8287                     for (; nb < nblim; nb += MAXE) MARKLO((*nb)->prev);
8288                 }
8289             }
8290         }
8291     }
8292 
8293     *nextP = Ptot;
8294     *nextQ = Qtot;
8295 }
8296 
8297 /**************************************************************************/
8298 
8299 static void
scanbipartite(int nbtot,int nbop,EDGE * wheelrim,int dosplit,EDGE * Pedges[],int nPedges)8300 scanbipartite(int nbtot, int nbop, EDGE *wheelrim, int dosplit,
8301               EDGE *Pedges[], int nPedges)
8302 
8303 /* The main node of the recursion for bipartite triangulations
8304    As this procedure is entered, nv,ne,degree etc are set for some graph,
8305    and nbtot/nbop are the values returned by canon() for that graph.
8306    If wheelrim != NULL, the input is a double wheel and *wheelrim is
8307    one of the edges on the rim.
8308    If dosplit==TRUE, this is the place to do splitting (if any).
8309    Splitting is a bit more complicated because the P operation adds
8310    two vertices.
8311    Pedges[0..nPedges-1] are edges of the graph that were reference
8312    edges for P-operations in ancestors of this graph.  They may not
8313    be reference edges for P-reductions now, but at least they are edges.
8314    However, if nPedges>0, we can say that certainly Pedges[nPedges-1]
8315    is a P-operation that was just done.
8316 */
8317 {
8318     EDGE *firstedge_save[MAXN];
8319     EDGE *extP[MAXE],*extQ[MAXE];
8320     EDGE *good_or[MAXE],*good_mir[MAXE];
8321     int ngood_or,ngood_mir,ngood_ref,ngood_mir_ref;
8322     int nextP,nextQ,i;
8323     int xnbtot,xnbop;
8324     EDGE *hint,*newPedges[MAXN/2];
8325 
8326     if (nv == maxnv)
8327     {
8328 	got_one(nbtot,nbop,3);
8329 	return;
8330     }
8331 
8332     if (dosplit)
8333     {
8334 #ifdef SPLITTEST
8335         ++splitcases;
8336         return;
8337 #endif
8338         if (splitcount-- != 0) return;
8339         splitcount = mod - 1;
8340 
8341         for (i = 0; i < nv; ++i) firstedge_save[i] = firstedge[i];
8342     }
8343 
8344 #ifdef PRE_FILTER_BIP
8345     if (!(PRE_FILTER_BIP)) return;
8346 #endif
8347 
8348 #ifndef FIND_EXTENSIONS_BIP
8349 #define FIND_EXTENSIONS_BIP find_extensions_bip
8350 #endif
8351 
8352     FIND_EXTENSIONS_BIP(nbtot,nbop,extP,&nextP,extQ,&nextQ,Pedges,nPedges);
8353 
8354     if (wheelrim && nv <= maxnv-2)
8355     {
8356         extend_bip_P(wheelrim);
8357 #ifdef FAST_FILTER_BIP
8358         if (FAST_FILTER_BIP)
8359 #endif
8360         {
8361             (void)canon(degree,numbering,&xnbtot,&xnbop);
8362             scanbipartite(xnbtot,xnbop,wheelrim,
8363                           nv==splitlevel||nv==splitlevel+1,Pedges,0);
8364 	}
8365         reduce_bip_P(wheelrim);
8366     }
8367 
8368     for (i = 0; i < nextP; ++i)
8369     {
8370         extend_bip_P(extP[i]);
8371 #ifdef FAST_FILTER_BIP
8372         if (FAST_FILTER_BIP)
8373 #endif
8374         {
8375 	    bip_P_legal(extP[i],good_or,&ngood_or,&ngood_ref,
8376 		        good_mir,&ngood_mir,&ngood_mir_ref,
8377 		        nPedges?Pedges[nPedges-1]:NULL);
8378             if (ngood_ref+ngood_mir_ref > 0)
8379 	    {
8380 	        if (nv == maxnv && !needgroup && ngood_or == ngood_ref
8381                                                 && ngood_mir == ngood_mir_ref)
8382 		    got_one(1,1,3);
8383 	        else if (ngood_or+ngood_mir==1)
8384 	        {
8385     		    Pedges[nPedges] = extP[i];
8386     		    scanbipartite(1,1,NULL,
8387                           nv==splitlevel||nv==splitlevel+1,Pedges,nPedges+1);
8388 	        }
8389 	        else if (canon_edge_oriented(good_or,ngood_or,ngood_ref,
8390                                            good_mir,ngood_mir,ngood_mir_ref,
8391                                            degree,numbering,&xnbtot,&xnbop))
8392 	        {
8393 		    Pedges[nPedges] = extP[i];
8394 	            scanbipartite(xnbtot,xnbop,NULL,
8395                          nv==splitlevel||nv==splitlevel+1,Pedges,nPedges+1);
8396 	        }
8397 	    }
8398 	}
8399 	reduce_bip_P(extP[i]);
8400     }
8401 
8402     hint = NULL;
8403     for (i = 0; i < nextQ; ++i)
8404     {
8405         extend_bip_Q(extQ[i]);
8406 #ifdef FAST_FILTER_BIP
8407         if (FAST_FILTER_BIP)
8408 #endif
8409         {
8410             if (!hint || !is_bip_P(hint)) hint = has_bip_P();
8411 
8412             if (!hint)
8413 	    {
8414 	        bip_Q_legal(extQ[i],good_or,&ngood_or,&ngood_ref,
8415                             good_mir,&ngood_mir,&ngood_mir_ref);
8416                 if (ngood_ref+ngood_mir_ref > 0
8417                     && canon_edge_oriented(good_or,ngood_or,ngood_ref,
8418                                            good_mir,ngood_mir,ngood_mir_ref,
8419                                            degree,numbering,&xnbtot,&xnbop))
8420 	           scanbipartite(xnbtot,xnbop,NULL,nv==splitlevel,newPedges,0);
8421 	    }
8422 	}
8423 	reduce_bip_Q(extQ[i]);
8424     }
8425 
8426     if (dosplit)
8427         for (i = 0; i < nv; ++i) firstedge[i] = firstedge_save[i];
8428 }
8429 
8430 /**************************************************************************/
8431 
8432 static void
update_nft_P(triangle nft[],int numnft,EDGE * ref,triangle newnft[],int * newnumnft)8433 update_nft_P(triangle nft[], int numnft, EDGE *ref,
8434                 triangle newnft[], int *newnumnft)
8435 
8436 /* Make new list of non-facial triangles after a P-extension. */
8437 {
8438     EDGE *refmin,*e,*elast;
8439     int i,k,w;
8440 
8441     refmin = ref->min;
8442 
8443   /* Remove triangles that include ref */
8444     k = 0;
8445     for (i = 0; i < numnft; ++i)
8446         if (nft[i].e1 != refmin && nft[i].e2 != refmin && nft[i].e3 != refmin)
8447             newnft[k++] = nft[i];
8448 
8449   /* Add new nfts formed by a shortcut if present.  There must be at
8450      least two nfts already for this to be possible. */
8451 
8452     if (k >= 2)
8453     {
8454         w = ref->next->end;
8455         elast = ref->invers->next->invers;
8456         for (e = elast->next->next->next->next; e != elast; e = e->next)
8457             if (e->end == w) break;
8458         if (e != elast)
8459         {
8460             newnft[k].e1 = e->min;
8461             newnft[k].e2 = ref->prev->min;
8462             newnft[k].e3 = ref->next->min;
8463             newnft[k+1].e1 = e->min;
8464             newnft[k+1].e2 = ref->next->next->invers->prev->min;
8465             newnft[k+1].e3 = ref->next->next->invers->next->min;
8466 	    k += 2;
8467         }
8468     }
8469     *newnumnft = k;
8470 }
8471 
8472 /**************************************************************************/
8473 
8474 static void
update_nft_Q(triangle nft[],int numnft,EDGE * ref,triangle newnft[],int * newnumnft)8475 update_nft_Q(triangle nft[], int numnft, EDGE *ref,
8476                 triangle newnft[], int *newnumnft)
8477 
8478 /* Make new list of non-facial triangles after a Q-extension. */
8479 {
8480     EDGE *refmin1,*refmin2,*e,*elast,*f,*flast;
8481     int i,k,w;
8482 
8483     refmin1 = ref->min;
8484     refmin2 = ref->next->min;
8485 
8486   /* Remove triangles that include ref or ref->next */
8487     k = 0;
8488     for (i = 0; i < numnft; ++i)
8489         if (nft[i].e1 != refmin1 && nft[i].e2 != refmin1
8490 		&& nft[i].e3 != refmin1 && nft[i].e1 != refmin2
8491 		&& nft[i].e2 != refmin2 && nft[i].e3 != refmin2)
8492             newnft[k++] = nft[i];
8493 
8494   /* Add new nft through ref if present */
8495 
8496     w = ref->end;
8497     elast = ref->next->next->invers->prev->prev;
8498     for (e = elast->next->next->next->next; e != elast; e = e->next)
8499         if (e->end == w) break;
8500     if (e != elast)
8501     {
8502         newnft[k].e1 = e->min;
8503         newnft[k].e2 = ref->min;
8504         newnft[k].e3 = ref->next->next->min;
8505         ++k;
8506     }
8507 
8508   /* Add new nft through ref->next if present */
8509 
8510     w = ref->next->end;
8511     elast = ref->invers->next->invers;
8512     for (e = elast->next->next->next->next; e != elast; e = e->next)
8513         if (e->end == w) break;
8514     if (e != elast)
8515     {
8516         newnft[k].e1 = e->min;
8517         newnft[k].e2 = ref->next->min;
8518         newnft[k].e3 = ref->prev->min;
8519         ++k;
8520     }
8521 
8522   /* Add all new nft's through the shortcut.  This is the only place
8523      an nft can be made where there was none before.  This code can
8524      also add extra nfts through ref or ref->next, since v can be
8525      ref->end or ref->next->end. */
8526 
8527     w = ref->prev->end;
8528     elast = ref->next->next->invers->prev->prev;
8529     for (e = elast->next->next->next; e != elast; e = e->next)
8530     {
8531 	flast = e->invers;
8532 	for (f = flast->next; f != flast; f = f->next)
8533 	    if (f->end == w) break;
8534 	if (f != flast)
8535 	{
8536 	    newnft[k].e1 = elast->next->min;
8537 	    newnft[k].e2 = e->min;
8538 	    newnft[k].e3 = f->min;
8539 	    ++k;
8540 	}
8541     }
8542 
8543     *newnumnft = k;
8544 }
8545 
8546 /**************************************************************************/
8547 
8548 static void
bipnftlaststep(EDGE * extP[],int * nextP,triangle nft[],int numnft)8549 bipnftlaststep(EDGE *extP[], int *nextP, triangle nft[], int numnft)
8550 
8551 /* Remove from extP[0..*nextP-1] those extensions which do not
8552    hit all of nft[0..numnft-1]. */
8553 {
8554     int i,j,k;
8555 
8556     for (j = 0; j < numnft; ++j)
8557     {
8558         RESETMARKS;
8559         MARKLO(nft[j].e1); MARKLO(nft[j].e1->invers);
8560         MARKLO(nft[j].e2); MARKLO(nft[j].e2->invers);
8561         MARKLO(nft[j].e3); MARKLO(nft[j].e3->invers);
8562 
8563         k = 0;
8564         for (i = 0; i < *nextP; ++i)
8565             if (ISMARKEDLO(extP[i])) extP[k++] = extP[i];
8566         *nextP = k;
8567     }
8568 }
8569 
8570 /**************************************************************************/
8571 
8572 static void
scanbipartite4c(int nbtot,int nbop,EDGE * wheelrim,int dosplit,EDGE * Pedges[],int nPedges,triangle nft[],int numnft)8573 scanbipartite4c(int nbtot, int nbop, EDGE *wheelrim, int dosplit,
8574               EDGE *Pedges[], int nPedges, triangle nft[], int numnft)
8575 
8576 /* The main node of the recursion for bipartite triangulations with
8577    monitoring of non-facial triangles.
8578    As this procedure is entered, nv,ne,degree etc are set for some graph,
8579    and nbtot/nbop are the values returned by canon() for that graph.
8580    If wheelrim != NULL, the input is a double wheel and *wheelrim is
8581    one of the edges on the rim.
8582    If dosplit==TRUE, this is the place to do splitting (if any).
8583    Splitting is a bit more complicated because the P operation adds
8584    two vertices.
8585    Pedges[0..nPedges-1] are edges of the graph that were reference
8586    edges for P-operations in ancestors of this graph.  They may not
8587    be reference edges for P-reductions now, but at least they are edges.
8588    However, if nPedges>0, we can say that certainly Pedges[nPedges-1]
8589    is a P-operation that was just done.
8590    nft[0..numnft-1] is a list of the non-facial triangles.
8591 */
8592 {
8593     EDGE *firstedge_save[MAXN];
8594     EDGE *extP[MAXE],*extQ[MAXE];
8595     EDGE *good_or[MAXE],*good_mir[MAXE];
8596     int ngood_or,ngood_mir,ngood_ref,ngood_mir_ref;
8597     int nextP,nextQ,i;
8598     int xnbtot,xnbop;
8599     EDGE *hint,*newPedges[MAXN/2];
8600     triangle newnft[MAXN];
8601     int newnumnft,connec;
8602 
8603     if (nv == maxnv)
8604     {
8605 	connec = 3 + (numnft==0);
8606 	if (connec >= minconnec) got_one(nbtot,nbop,connec);
8607 	return;
8608     }
8609 
8610     if (dosplit)
8611     {
8612 #ifdef SPLITTEST
8613         ++splitcases;
8614         return;
8615 #endif
8616         if (splitcount-- != 0) return;
8617         splitcount = mod - 1;
8618 
8619         for (i = 0; i < nv; ++i) firstedge_save[i] = firstedge[i];
8620     }
8621 
8622 #ifdef PRE_FILTER_BIP
8623     if (!(PRE_FILTER_BIP)) return;
8624 #endif
8625 
8626 #ifndef FIND_EXTENSIONS_BIP
8627 #define FIND_EXTENSIONS_BIP find_extensions_bip
8628 #endif
8629 
8630     FIND_EXTENSIONS_BIP(nbtot,nbop,extP,&nextP,extQ,&nextQ,Pedges,nPedges);
8631 
8632     if (nv == maxnv-2 && numnft > 0 && minconnec == 4)
8633         bipnftlaststep(extP,&nextP,nft,numnft);
8634 
8635     if (wheelrim && nv <= maxnv-2)
8636     {
8637         extend_bip_P(wheelrim);
8638 #ifdef FAST_FILTER_BIP
8639         if (FAST_FILTER_BIP)
8640 #endif
8641         {
8642             canon(degree,numbering,&xnbtot,&xnbop);
8643             scanbipartite4c(xnbtot,xnbop,wheelrim,
8644                      nv==splitlevel||nv==splitlevel+1,Pedges,0,nft,numnft);
8645 	}
8646         reduce_bip_P(wheelrim);
8647     }
8648 
8649     for (i = 0; i < nextP; ++i)
8650     {
8651         extend_bip_P(extP[i]);
8652 #ifdef FAST_FILTER_BIP
8653         if (FAST_FILTER_BIP)
8654 #endif
8655         {
8656 	    bip_P_legal(extP[i],good_or,&ngood_or,&ngood_ref,
8657 		        good_mir,&ngood_mir,&ngood_mir_ref,
8658 		        nPedges?Pedges[nPedges-1]:NULL);
8659             if (ngood_ref+ngood_mir_ref > 0)
8660 	    {
8661 	        if (nv == maxnv && !needgroup && ngood_or == ngood_ref
8662                                                 && ngood_mir == ngood_mir_ref)
8663 	        {
8664 		    update_nft_P(nft,numnft,extP[i],newnft,&newnumnft);
8665 		    connec = 3 + (newnumnft==0);
8666 		    if (connec >= minconnec) got_one(1,1,connec);
8667 	        }
8668 	        else if (ngood_or+ngood_mir==1)
8669 	        {
8670 		    update_nft_P(nft,numnft,extP[i],newnft,&newnumnft);
8671     		    Pedges[nPedges] = extP[i];
8672     		    scanbipartite4c(1,1,NULL,nv==splitlevel||nv==splitlevel+1,
8673 			            Pedges,nPedges+1,newnft,newnumnft);
8674 	        }
8675 	        else if (canon_edge_oriented(good_or,ngood_or,ngood_ref,
8676                                            good_mir,ngood_mir,ngood_mir_ref,
8677                                            degree,numbering,&xnbtot,&xnbop))
8678 	        {
8679 		    update_nft_P(nft,numnft,extP[i],newnft,&newnumnft);
8680 		    Pedges[nPedges] = extP[i];
8681 	            scanbipartite4c(xnbtot,xnbop,NULL,
8682 			            nv==splitlevel||nv==splitlevel+1,
8683 				    Pedges,nPedges+1,newnft,newnumnft);
8684 	        }
8685 	    }
8686 	}
8687 	reduce_bip_P(extP[i]);
8688     }
8689 
8690     hint = NULL;
8691     for (i = 0; i < nextQ; ++i)
8692     {
8693         extend_bip_Q(extQ[i]);
8694 #ifdef FAST_FILTER_BIP
8695         if (FAST_FILTER_BIP)
8696 #endif
8697         {
8698             if (!hint || !is_bip_P(hint)) hint = has_bip_P();
8699 
8700             if (!hint)
8701 	    {
8702 	        bip_Q_legal(extQ[i],good_or,&ngood_or,&ngood_ref,
8703                             good_mir,&ngood_mir,&ngood_mir_ref);
8704                 if (ngood_ref+ngood_mir_ref > 0
8705                     && canon_edge_oriented(good_or,ngood_or,ngood_ref,
8706                                            good_mir,ngood_mir,ngood_mir_ref,
8707                                            degree,numbering,&xnbtot,&xnbop))
8708 	        {
8709 		    update_nft_Q(nft,numnft,extQ[i],newnft,&newnumnft);
8710 		    scanbipartite4c(xnbtot,xnbop,NULL,nv==splitlevel,
8711 				    newPedges,0,newnft,newnumnft);
8712 	        }
8713 	    }
8714 	}
8715 	reduce_bip_Q(extQ[i]);
8716     }
8717 
8718     if (dosplit)
8719         for (i = 0; i < nv; ++i) firstedge[i] = firstedge_save[i];
8720 }
8721 
8722 /**************************************************************************/
8723 
8724 static void
extend_four(EDGE * ref)8725 extend_four(EDGE *ref)
8726 
8727 /* This routine is another implementation of the 4-operation
8728    in Batagelj's paper.
8729 */
8730 {
8731     register EDGE *a,*b,*start,*dummy;
8732 
8733     start=four_op(nv);
8734     b=ref->next->invers;
8735     a=b->next;
8736 
8737     degree[nv]=4; firstedge[nv]=start;
8738 
8739     dummy=start+1;
8740     start->end=dummy->start=a->start;
8741     (degree[a->start])++;
8742     a->prev=b->next=dummy;
8743     dummy->prev=b; dummy->next=a;
8744 
8745     b=b->invers; a=ref->prev;
8746 
8747     start+=2; /*2*/ dummy=start+1;
8748     start->end=dummy->start=b->start;
8749     firstedge[b->start]=dummy;
8750     b->prev=a->next=dummy;
8751     dummy->prev=a; dummy->next=b;
8752 
8753     a=a->invers; b=a->prev;
8754     start+=2; /*4*/ dummy=start+1;
8755     start->end=dummy->start=b->start;
8756     (degree[b->start])++;
8757     a->prev=b->next=dummy;
8758     dummy->prev=b; dummy->next=a;
8759 
8760     start->next=(start-4)->prev=ref;
8761     ref->next=start-4; ref->prev=start;
8762     ref->start=ref->invers->end=nv;
8763 
8764     nv++;
8765     ne+=6;
8766 }
8767 
8768 /**************************************************************************/
8769 
8770 static int
is_min4_four(EDGE * ref)8771 is_min4_four(EDGE *ref)
8772 
8773 /* Test if ref (known to be an edge!) is the reference edge of a
8774    legal four-reduction in the min4 case.
8775    Return 1 if it is, and 0 if it isn't.
8776 */
8777 {
8778     int w;
8779     EDGE *e,*elast;
8780 
8781     if (degree[ref->start] != 4) return 0;
8782     if (degree[ref->prev->end] == 4 || degree[ref->next->end] == 4) return 0;
8783 
8784     w = ref->next->next->end;
8785     if (degree[w] == 4) return 1;
8786     e = ref->invers;
8787     elast = e->prev;
8788     for (e = e->next->next; e != elast; e = e->next)
8789 	if (e->end == w) return 0;
8790 
8791     return 1;
8792 }
8793 
8794 /**************************************************************************/
8795 
8796 static void
reduce_four(EDGE * ref)8797 reduce_four(EDGE *ref)
8798 
8799 /* The reverse of extend_four(ref) */
8800 {
8801     register EDGE *a,*b;
8802 
8803     a=ref->invers->prev->invers;
8804     b=a->prev->prev;
8805 
8806     a->prev=b; b->next=a;
8807     firstedge[a->start]=a; (degree[a->start])--;
8808 
8809     a=b->invers; b=a->prev->prev;
8810     a->prev=b->next=ref;
8811     ref->next=a; ref->prev=b;
8812     ref->start=ref->invers->end=a->start;
8813     firstedge[a->start]=a;
8814 
8815     a=b->invers; b=a->prev->prev;
8816     a->prev=b; b->next=a;
8817     firstedge[a->start]=a; (degree[a->start])--;
8818 
8819     nv--;
8820     ne-=6;
8821 }
8822 
8823 /**************************************************************************/
8824 
8825 static void
prune_oriented_lists(EDGE * good_or[],int * ngood_or,int * ngood_ref,EDGE * good_mir[],int * ngood_mir,int * ngood_mir_ref)8826 prune_oriented_lists(EDGE *good_or[], int *ngood_or, int *ngood_ref,
8827                      EDGE *good_mir[], int *ngood_mir, int *ngood_mir_ref)
8828 
8829 /* Try to prune the edge lists (of the form required by
8830    canon_edge_oriented()) by using the degrees of a couple of
8831    extra vertices.  The result is returned in the same form.
8832    As always, if *ngood_ref==*ngood_mir_ref==0 on output
8833    (which must not be true on input), all else is undefined.
8834 */
8835 {
8836     int i,k,kref;
8837     long code_or[MAXE],code_mir[MAXE],maxcode;
8838 #define PRUNE_OR(e) ((degree[(e)->invers->prev->prev->end] << 10) \
8839 		      + degree[(e)->next->invers->prev->end])
8840 #define PRUNE_MIR(e) ((degree[(e)->invers->next->next->end] << 10) \
8841                       + degree[(e)->prev->invers->next->end])
8842 
8843     maxcode = 0;
8844     for (i = 0; i < *ngood_or; ++i)
8845     {
8846 	code_or[i] = PRUNE_OR(good_or[i]);
8847 	if (code_or[i] > maxcode) maxcode = code_or[i];
8848     }
8849 
8850     for (i = 0; i < *ngood_mir; ++i)
8851     {
8852         code_mir[i] = PRUNE_MIR(good_mir[i]);
8853         if (code_mir[i] > maxcode) maxcode = code_mir[i];
8854     }
8855 
8856     k = kref = 0;
8857     for (i = 0; i < *ngood_or; ++i)
8858         if (code_or[i] == maxcode)
8859 	{
8860 	    if (i < *ngood_ref) ++kref;
8861 	    good_or[k++] = good_or[i];
8862 	}
8863     *ngood_or = k;
8864     *ngood_ref = kref;
8865 
8866     k = kref = 0;
8867     for (i = 0; i < *ngood_mir; ++i)
8868         if (code_mir[i] == maxcode)
8869         {
8870             if (i < *ngood_mir_ref) ++kref;
8871             good_mir[k++] = good_mir[i];
8872         }
8873     *ngood_mir = k;
8874     *ngood_mir_ref = kref;
8875 }
8876 
8877 /**************************************************************************/
8878 
8879 static void
min4_four_legal(EDGE * ref,EDGE * good_or[],int * ngood_or,int * ngood_ref,EDGE * good_mir[],int * ngood_mir,int * ngood_mir_ref)8880 min4_four_legal(EDGE *ref, EDGE *good_or[], int *ngood_or, int *ngood_ref,
8881                 EDGE *good_mir[], int *ngood_mir, int *ngood_mir_ref)
8882 
8883 /* The four-operation with reference edge *ref has just been performed.
8884    Make a list in good_or[0..*ngood_or-1] of the reference edges of
8885    legal four-reductions (oriented editions) that might be canonical,
8886    with the first *ngood_ref of those being ref.
8887    Make a list in good_mir[0..*ngood_mir-1] of the
8888    reference edges of legal four-reductions (mirror-image editions)
8889    that might be canonical, with the first *ngood_mir_ref of those being
8890    ref->next.
8891    *ngood_ref and *ngood_mir_ref might each be 0-2.  If they are
8892    both 0, nothing else need be correct.
8893    All the edges in good_or[] and good_mir[] must start with the same
8894    vertex degree and end with the same vertex degree (actually, colour
8895    as passed to canon_edge_oriented).
8896    Four-reductions have a priority: (maxdeg, mindeg) where those are
8897    the two degrees on the subdivided diagonal.  Bigger = better.
8898 */
8899 {
8900     EDGE *e,*er;
8901     long deg1,deg2,deg3,deg4;
8902 #define FOURTYPE(d3,d4) (((d3)<<10)+(d4))
8903     long besttype,etype1,etype2,ertype1,ertype2,etype,ertype;
8904     int bestdeg,nextdeg,nor,nmir,i,w;
8905     EDGE *ei,*eilast;
8906 
8907     e = ref;
8908     er = ref->next->next;
8909     deg1 = degree[e->end];
8910     deg2 = degree[er->end];
8911     deg3 = degree[e->prev->end];
8912     deg4 = degree[e->next->end];
8913 
8914     nor = nmir = 0;
8915 
8916     if (deg1 >= deg2)
8917     {
8918         bestdeg = deg1; nextdeg = deg2;
8919         etype1 = FOURTYPE(deg3,deg4);
8920         etype2 = FOURTYPE(deg4,deg3);
8921         besttype = etype = etype1 > etype2 ? etype1 : etype2;
8922     }
8923 
8924     if (deg1 <= deg2)
8925     {
8926         bestdeg = deg2; nextdeg = deg1;
8927         ertype1 = FOURTYPE(deg4,deg3);
8928         ertype2 = FOURTYPE(deg3,deg4);
8929 	besttype = ertype = ertype1 > ertype2 ? ertype1 : ertype2;
8930     }
8931 
8932     if (deg1 == deg2) besttype = etype > ertype ? etype : ertype;
8933 
8934     if (deg1 >= deg2)
8935     {
8936 	if (etype1 == besttype) good_or[nor++] = e;
8937 	if (etype2 == besttype) good_mir[nmir++] = e;
8938     }
8939     if (deg1 <= deg2)
8940     {
8941         if (ertype1 == besttype) good_or[nor++] = er;
8942         if (ertype2 == besttype) good_mir[nmir++] = er;
8943     }
8944 
8945     *ngood_ref = nor;
8946     *ngood_mir_ref = nmir;
8947 
8948     RESETMARKS;
8949     MARKLO(e->invers);
8950     MARKLO(er->invers);
8951 
8952     for (i = 0; i < nv; ++i)
8953     if (degree[i] > bestdeg)
8954     {
8955 	ei = eilast = firstedge[i];
8956 	do
8957 	{
8958 	    if (degree[ei->end] == 4 && is_min4_four(ei->invers))
8959 	    {
8960 		*ngood_ref = *ngood_mir_ref = 0;
8961 		return;
8962 	    }
8963 	    ei = ei->next;
8964 	} while (ei != eilast);
8965     }
8966     else if (degree[i] == bestdeg)
8967     {
8968         ei = eilast = firstedge[i];
8969         do
8970         {
8971             if (degree[ei->end] == 4 && !ISMARKEDLO(ei))
8972 	    {
8973 		e = ei->invers;
8974 	  	er = e->next->next;
8975 		w = er->end;
8976 		deg2 = degree[w];
8977 		if (deg2 > nextdeg && is_min4_four(e))
8978 		{
8979                     *ngood_ref = *ngood_mir_ref = 0;
8980                     return;
8981                 }
8982 		else if (deg2 == nextdeg && (bestdeg > nextdeg || i < w)
8983 					 && is_min4_four(e))
8984 		{
8985 		    deg3 = degree[e->prev->end];
8986 		    deg4 = degree[e->next->end];
8987                     etype1 = FOURTYPE(deg3,deg4);
8988                     etype2 = FOURTYPE(deg4,deg3);
8989 
8990                     if (etype1 > besttype || etype2 > besttype)
8991                     {
8992                         *ngood_ref = *ngood_mir_ref = 0;
8993                         return;
8994                     }
8995                     if (etype1 == besttype) good_or[nor++] = e;
8996                     if (etype2 == besttype) good_mir[nmir++] = e;
8997 
8998 		    if (nextdeg == bestdeg)
8999 		    {
9000                 	ertype1 = FOURTYPE(deg4,deg3);
9001                 	ertype2 = FOURTYPE(deg3,deg4);
9002 
9003                 	if (ertype1 > besttype || ertype2 > besttype)
9004                 	{
9005                     	    *ngood_ref = *ngood_mir_ref = 0;
9006                     	    return;
9007                 	}
9008 
9009                 	if (ertype1 == besttype) good_or[nor++] = er;
9010                 	if (ertype2 == besttype) good_mir[nmir++] = er;
9011 		    }
9012 		}
9013 	    }
9014 	    ei = ei->next;
9015 	} while (ei != eilast);
9016     }
9017 
9018     if (nor > *ngood_ref || nmir > *ngood_mir_ref)
9019         prune_oriented_lists(good_or,&nor,ngood_ref,
9020                              good_mir,&nmir,ngood_mir_ref);
9021 
9022     *ngood_or = nor;
9023     *ngood_mir = nmir;
9024 }
9025 
9026 /**************************************************************************/
9027 
9028 static int
min4_four_centre(void)9029 min4_four_centre(void)
9030 
9031 /* If there is a four-reduction, return the central vertex.
9032    If not, return -1.
9033 */
9034 {
9035     int i;
9036     EDGE *e;
9037 
9038     for (i = 0; i < nv; ++i)
9039     if (degree[i] == 4)
9040     {
9041 	e = firstedge[i];
9042 	if ((degree[e->prev->end] >= 5 && degree[e->next->end] >= 5)
9043 	   || (degree[e->end] >= 5 && degree[e->next->next->end] >= 5))
9044 		return i;
9045     }
9046 
9047     return -1;
9048 }
9049 
9050 /*************************************************************************/
9051 
9052 static int
is_min4_four_centre(int v)9053 is_min4_four_centre(int v)
9054 
9055 /* return 1 if v is the centre of a four-reduction, 0 if not.
9056 */
9057 {
9058     EDGE *e;
9059 
9060     if (degree[v] != 4) return 0;
9061 
9062     e = firstedge[v];
9063     if ((degree[e->prev->end] >= 5 && degree[e->next->end] >= 5)
9064 	|| (degree[e->end] >= 5 && degree[e->next->next->end] >= 5))
9065         return 1;
9066     else
9067 	return 0;
9068 }
9069 
9070 /*************************************************************************/
9071 
9072 static int
has_3_four_centres(void)9073 has_3_four_centres(void)
9074 
9075 /* Return 1 if there are at least three vertices which are centres
9076    for a four-reduction (min4 case).  Return 0 otherwise.
9077 */
9078 {
9079     EDGE *e;
9080     int v,count;
9081 
9082     count = 0;
9083     for (v = nv; --v >= 0;)
9084     if (degree[v] == 4)
9085     {
9086 	e = firstedge[v];
9087         if ((degree[e->prev->end] >= 5 && degree[e->next->end] >= 5)
9088 	    || (degree[e->end] >= 5 && degree[e->next->next->end] >= 5))
9089         {
9090 	    if (++count == 3) return 1;
9091 	}
9092     }
9093 
9094     return count >= 3;
9095 }
9096 
9097 /*************************************************************************/
9098 
9099 static int
degree5_vertex(void)9100 degree5_vertex(void)
9101 
9102 /* Return a vertex of degree 5, -1 if there are none */
9103 {
9104     int i;
9105 
9106     for (i = 0; i < nv; ++i)
9107 	if (degree[i] == 5) return 1;
9108 
9109     return -1;
9110 }
9111 
9112 /*************************************************************************/
9113 
9114 static void
extend_five(EDGE * ref)9115 extend_five(EDGE *ref)
9116 
9117 /* This routine is another implementation of the five-operation
9118    in Batagelj's paper. */
9119 {
9120     EDGE *a,*b,*start,*dummy;
9121 
9122     start=five_op(nv);
9123     degree[nv]=5; firstedge[nv]=start;
9124 
9125 
9126     b=ref->prev;
9127     a=ref->next;
9128     dummy=start+1;
9129     b->next=a->prev=dummy;
9130     dummy->next=a; dummy->prev=b;
9131     dummy->start=start->end=a->start;
9132     firstedge[a->start]=a;
9133 
9134     a=b->invers; b=a->prev;
9135     start +=2; /*2*/ dummy=start+1;
9136     b->next=a->prev=dummy;
9137     dummy->next=a; dummy->prev=b;
9138     dummy->start=start->end=a->start;
9139     (degree[a->start])++;
9140 
9141     a=b->invers; b=a->prev->prev->prev; dummy=ref->invers;
9142     b->next=dummy;
9143     dummy->prev=b;
9144     firstedge[a->start]=a;
9145     (degree[a->start])--;
9146 
9147     a=b->invers; b=a->prev;
9148     start +=2; /*4*/ dummy=start+1;
9149     b->next=a->prev=dummy;
9150     dummy->next=a; dummy->prev=b;
9151     dummy->start=start->end=a->start;
9152     (degree[a->start])++;
9153 
9154     dummy=b->invers->prev->invers; /* the other remaining edge of the "v" */
9155 
9156     dummy->start=dummy->invers->end=nv;
9157     dummy->next=start-4; dummy->prev=start;
9158     start->next=dummy; (start-4)->prev=dummy;
9159 
9160     ref->start=ref->invers->end=nv;
9161     ref->next=start; ref->prev=start-2;
9162     start->prev=ref; (start-2)->next=ref;
9163 
9164     nv++;
9165     ne+=6;
9166 }
9167 
9168 /**************************************************************************/
9169 
9170 static void
reduce_five(EDGE * ref)9171 reduce_five(EDGE *ref)
9172 
9173 /* The reverse of extend_five(). */
9174 {
9175     EDGE *a,*b,*dummy;
9176 
9177     a=ref->next->next; dummy=ref->invers; b=dummy->prev;
9178     dummy->prev=b->next=a; a->next=dummy; a->prev=b;
9179     a->start=a->invers->end=dummy->start;
9180     (degree[dummy->start])++;
9181 
9182     a=b->invers; b=a->prev->prev;
9183     a->prev=b; b->next=a;
9184     (degree[a->start])--;
9185     firstedge[a->start]=a;
9186 
9187     a=b->invers->prev->prev->invers; b=a->prev->prev;
9188     a->prev=ref; ref->next=a; b->next=ref; ref->prev=b;
9189     ref->start=ref->invers->end=a->start;
9190     firstedge[a->start]=a;
9191 
9192     a=b->invers; b=a->prev->prev;
9193     a->prev=b; b->next=a;
9194     (degree[a->start])--;
9195     firstedge[a->start]=a;
9196 
9197     nv--;
9198     ne-=6;
9199 }
9200 
9201 /**************************************************************************/
9202 
9203 static void
min4_five_legal(EDGE * ref,EDGE * good_or[],int * ngood_or,int * ngood_ref,EDGE * good_mir[],int * ngood_mir,int * ngood_mir_ref)9204 min4_five_legal(EDGE *ref, EDGE *good_or[], int *ngood_or, int *ngood_ref,
9205                 EDGE *good_mir[], int *ngood_mir, int *ngood_mir_ref)
9206 
9207 /* The five-operation with reference edge *ref has just been performed.
9208    Make a list in good_or[0..*ngood_or-1] of the reference edges of
9209    legal five-reductions (oriented editions) that might be canonical,
9210    with the first *ngood_ref of those being ref.
9211    Make a list in good_mir[0..*ngood_mir-1] of the
9212    reference edges of legal five-reductions (mirror-image editions)
9213    that might be canonical, with the first *ngood_mir_ref of those being
9214    ref.
9215    *ngood_ref and *ngood_mir_ref might each be 0 or 1.  If they are
9216    both 0, nothing else need be correct.
9217    All the edges in good_or[] and good_mir[] must start with the same
9218    vertex degree and end with the same vertex degree (actually, colour
9219    as passed to canon_edge_oriented).
9220 */
9221 {
9222     EDGE *e;
9223     long deg1,deg2,deg3,bestdeg;
9224 #define FIVETYPE(d1,d2,d3) (((d1)<<21)+((d2)<<11)+(d3))
9225     long besttype,type1,type2;
9226     int nor,nmir,i,j,v,w;
9227     EDGE *ez,*ezlast;
9228 
9229     e = ref;
9230     bestdeg = degree[e->end];
9231     deg2 = degree[e->prev->end];
9232     deg3 = degree[e->next->end];
9233 
9234     type1 = FIVETYPE(bestdeg,deg2,deg3);
9235     type2 = FIVETYPE(bestdeg,deg3,deg2);
9236     besttype = type1 > type2 ? type1 : type2;
9237 
9238     nor = nmir = 0;
9239     if (type1 == besttype) good_or[nor++] = e;
9240     if (type2 == besttype) good_mir[nmir++] = e;
9241 
9242     *ngood_ref = nor;
9243     *ngood_mir_ref = nmir;
9244 
9245     for (i = 0; i < nv; ++i)
9246     if (degree[i] == 5)
9247     {
9248 	for (e = firstedge[i], j = 0; j < 5; ++j, e = e->next)
9249         {
9250 	    if (e == ref) continue;
9251             deg1 = degree[e->end];
9252 	    if (deg1 < bestdeg) continue;
9253 	    deg2 = degree[e->prev->end];
9254 	    if (deg2 == 4) continue;
9255 	    deg3 = degree[e->next->end];
9256 	    if (deg3 == 4) continue;
9257 
9258 	    v = e->next->next->end;
9259 	    w = e->next->next->next->end;
9260 	    ez = e->invers;
9261 	    ezlast = ez->prev;
9262 	    for (ez = ez->next->next; ez != ezlast; ez = ez->next)
9263 	        if (ez->end == w || ez->end == v) break;
9264 	    if (ez != ezlast) continue;
9265 
9266 	    if (deg1 > bestdeg)
9267 	    {
9268 		*ngood_ref = *ngood_mir_ref = 0;
9269 		return;
9270 	    }
9271 
9272 	    type1 = FIVETYPE(deg1,deg2,deg3);
9273     	    type2 = FIVETYPE(deg1,deg3,deg2);
9274 
9275 	    if (type1 > besttype || type2 > besttype)
9276 	    {
9277                 *ngood_ref = *ngood_mir_ref = 0;
9278                 return;
9279             }
9280     	    if (type1 == besttype) good_or[nor++] = e;
9281     	    if (type2 == besttype) good_mir[nmir++] = e;
9282         }
9283     }
9284 
9285     *ngood_or = nor;
9286     *ngood_mir = nmir;
9287 }
9288 
9289 /**************************************************************************/
9290 
9291 static void
extend_S(EDGE * ref)9292 extend_S(EDGE *ref)
9293 
9294 /* This routine is the implementation of the S-operation in Batagelj's paper.
9295    It inserts 3 new vertices in triangular form into a triangle on the right
9296    hand side of ref */
9297 
9298 {
9299     register EDGE *a,*b,*start;
9300     int dummy;
9301 
9302     start=S_op(nv);
9303 
9304     a=ref->invers->prev;
9305     b=a->invers->prev;
9306 
9307     degree[nv]=degree[nv+1]=degree[nv+2]=4;
9308 
9309     dummy=ref->start;
9310     degree[dummy]+=2;
9311     (start+10)->start=(start+11)->end=(start+8)->start=(start+9)->end=dummy;
9312 
9313     dummy=ref->end;
9314     degree[dummy]+=2;
9315     (start+12)->start=(start+13)->end=(start+14)->start=(start+15)->end=dummy;
9316 
9317     dummy=a->end;
9318     degree[dummy]+=2;
9319     (start+6)->start=(start+7)->end=(start+16)->start=(start+17)->end=dummy;
9320 
9321     firstedge[nv]=start+1;
9322     firstedge[nv+1]=start;
9323     firstedge[nv+2]=start+2;
9324 
9325     ref->next=start+10; (start+10)->prev=ref;
9326     a->next=start+14; (start+14)->prev=a;
9327     b->next=start+6; (start+6)->prev=b;
9328 
9329     ref=ref->invers;
9330     ref->prev=start+12; (start+12)->next=ref;
9331     a=a->invers;
9332     a->prev=start+16; (start+16)->next=a;
9333     b=b->invers;
9334     b->prev=start+8; (start+8)->next=b;
9335 
9336     nv+=3;
9337     ne+=18;
9338 }
9339 
9340 /**************************************************************************/
9341 
9342 static void
reduce_S(EDGE * ref)9343 reduce_S(EDGE *ref)
9344 
9345 /* This routine is the implementation of the inverse S-operation in
9346    Batagelj's paper. It removes the triangle.
9347 */
9348 {
9349     register EDGE *a,*b;
9350 
9351     a=ref->invers->prev->prev->prev;
9352     b=a->invers->prev->prev->prev;
9353 
9354     firstedge[ref->start]=ref;
9355     degree[ref->start]-=2;
9356     firstedge[a->start]=a;
9357     degree[a->start]-=2;
9358     firstedge[b->start]=b;
9359     degree[b->start]-=2;
9360 
9361     ref->next=b->invers; b->invers->prev=ref;
9362     a->next=ref->invers; ref->invers->prev=a;
9363     b->next=a->invers; a->invers->prev=b;
9364 
9365     nv-=3;
9366     ne-=18;
9367 }
9368 
9369 /**************************************************************************/
9370 
9371 static void
min4_S_legal(EDGE * ref,EDGE * good_or[],int * ngood_or,int * ngood_ref,EDGE * good_mir[],int * ngood_mir,int * ngood_mir_ref)9372 min4_S_legal(EDGE *ref, EDGE *good_or[], int *ngood_or, int *ngood_ref,
9373              EDGE *good_mir[], int *ngood_mir, int *ngood_mir_ref)
9374 
9375 /* The S-operation with reference edge *ref has just been performed.
9376    Make a list in good_or[0..*ngood_or-1] of the reference edges of
9377    legal S-reductions (oriented editions) that might be canonical,
9378    with the first *ngood_ref of those being ref.
9379    Make a list in good_mir[0..*ngood_mir-1] of the
9380    reference edges of legal S-reductions (mirror-image editions)
9381    that might be canonical, with the first *ngood_mir_ref of those
9382    being ref.
9383    *ngood_ref and *ngood_mir_ref might each be 0 or 1.  If they are
9384    both 0, nothing else need be correct.
9385    All the edges in good_or[] and good_mir[] must start with the same
9386    vertex degree and end with the same vertex degree (actually, colour
9387    as passed to canon_edge_oriented).
9388 
9389    Hopefully this routine is used rarely, so we are going for simple
9390    rather than fast.  If the S operation ever becomes a critical part
9391    of some generation, optimising this routine would be necesary.
9392 */
9393 {
9394     EDGE *e,*ee;
9395     int nor,nmir,i,j;
9396 
9397     RESETMARKS;
9398     e = ref;
9399 
9400     nor = nmir = 0;
9401     good_or[nor++] = e;
9402     good_mir[nmir++] = e->invers;
9403     MARKLO(e);
9404 
9405     ee = e->invers->prev->prev->prev;
9406     good_or[nor++] = ee;
9407     good_mir[nmir++] = ee->invers;
9408     MARKLO(ee);
9409 
9410     ee = ee->invers->prev->prev->prev;
9411     good_or[nor++] = ee;
9412     good_mir[nmir++] = ee->invers;
9413     MARKLO(ee);
9414 
9415     *ngood_ref = nor;
9416     *ngood_mir_ref = nmir;
9417 
9418     for (i = 0; i < nv; ++i)
9419     if (degree[i] >= 6)
9420     {
9421 	for (e = firstedge[i], j = degree[i]; --j >= 0; e = e->next)
9422         {
9423 	    if (ISMARKEDLO(e)) continue;
9424             if (degree[e->end] < 6 || degree[e->next->end] != 4 ||
9425 		degree[e->next->next->end] != 4 ||
9426 		degree[e->next->next->next->end] < 6) continue;
9427 	    if (degree[e->next->invers->next->next->end] != 4) continue;
9428 
9429 	    good_or[nor++] = e;
9430             good_mir[nmir++] = e->invers;
9431             MARKLO(e);
9432 
9433             ee = e->invers->prev->prev->prev;
9434             good_or[nor++] = ee;
9435             good_mir[nmir++] = ee->invers;
9436             MARKLO(ee);
9437 
9438             ee = ee->invers->prev->prev->prev;
9439             good_or[nor++] = ee;
9440             good_mir[nmir++] = ee->invers;
9441             MARKLO(ee);
9442         }
9443     }
9444 
9445     *ngood_or = nor;
9446     *ngood_mir = nmir;
9447 }
9448 
9449 /**************************************************************************/
9450 
9451 static void
find_extensions_min4_four(int nbtot,EDGE * ext4[],int * next4,EDGE * known)9452 find_extensions_min4_four(int nbtot, EDGE *ext4[], int *next4, EDGE *known)
9453 
9454 /* nbtot is the number of automorphisms.  If known!=NULL, it is the
9455    reference edge of a canonical four-extension just used to make the
9456    graph.  See min4_four_legal() for important comments about what makes
9457    a four-extension canonical.  This procedure makes a list in
9458    ext4[0..*next4-1] of undirected edges whose use in a four-extension
9459    might possible be canonical.
9460 */
9461 {
9462     int deg1,deg2,deg3,dega,degb;
9463     int i,v,k,kk;
9464     EDGE *e,*elast,*ez,*ezlim,*e2;
9465     EDGE **nb,**nb0,**nblim;
9466 
9467     RESETMARKS;
9468     k = 0;
9469 
9470     if (known)
9471     {
9472 	deg1 = degree[known->end];
9473 	deg2 = degree[known->next->next->end];
9474 	if (deg1 < deg2)
9475         {
9476 	    i = deg1; deg1 = deg2; deg2 = i;
9477 	    known = known->next->next;
9478 	}
9479 
9480 	ez = known->invers;
9481 	ezlim = ez->prev;
9482 	deg3 = 0;
9483 	for (ez = ez->next->next; ez != ezlim; ez = ez->next)
9484 	{
9485    	    if (is_min4_four(ez->invers))
9486 	    {
9487 		kk = degree[ez->invers->next->next->end];
9488 		if (kk > deg3)
9489 		{
9490 		    deg3 = kk;
9491 		    e2 = ez;
9492 		}
9493 	    }
9494 	}
9495 
9496 	if (deg3 == 0)
9497 	{
9498           /* edges around the outside */
9499 	    e = known->invers->next;
9500 	    ext4[k++] = e; MARKLO(e); MARKLO(e->invers);
9501 	    e = e->invers->next->next;
9502 	    ext4[k++] = e; MARKLO(e); MARKLO(e->invers);
9503 	    e = e->invers->next->next;
9504 	    ext4[k++] = e; MARKLO(e); MARKLO(e->invers);
9505 	    e = e->invers->next->next;
9506 	    ext4[k++] = e; MARKLO(e); MARKLO(e->invers);
9507 
9508           /* edges in the middle */
9509 	    e = known;
9510 	    ext4[k++] = e; MARKLO(e); MARKLO(e->invers);
9511 	    e = e->next;
9512 	    ext4[k++] = e; MARKLO(e); MARKLO(e->invers);
9513             e = e->next;
9514             if (deg2 == deg1)
9515             {
9516                 ext4[k++] = e; MARKLO(e); MARKLO(e->invers);
9517             }
9518             e = e->next;
9519             ext4[k++] = e; MARKLO(e); MARKLO(e->invers);
9520 	}
9521 	else
9522         {
9523 	    dega = degree[known->prev->end];
9524 	    degb = degree[known->next->end];
9525 
9526           /* edges around the outside */
9527             e = known->invers->next;
9528 	    if (dega >= deg3 || e->next == e2)
9529 	    {
9530                 ext4[k++] = e; MARKLO(e); MARKLO(e->invers);
9531 	    }
9532 
9533             e = e->invers->next->next;
9534 	    if (deg1 == deg2 && dega >= deg3)
9535 	    {
9536                 ext4[k++] = e; MARKLO(e); MARKLO(e->invers);
9537 	    }
9538 
9539             e = e->invers->next->next;
9540 	    if (deg1 == deg2 && degb >= deg3)
9541 	    {
9542                 ext4[k++] = e; MARKLO(e); MARKLO(e->invers);
9543 	    }
9544 
9545             e = e->invers->next->next;
9546 	    if (degb >= deg3 || e->invers->prev == e2)
9547 	    {
9548                 ext4[k++] = e; MARKLO(e); MARKLO(e->invers);
9549 	    }
9550 
9551           /* edges in the middle */
9552             e = known;
9553             if (deg3 == 4)
9554             {
9555                 ext4[k++] = e; MARKLO(e); MARKLO(e->invers);
9556             }
9557 
9558             e = e->next;
9559 	    if (degb > deg1+1 || (degb == deg1+1 && deg3 == 4))
9560 	    {
9561                 ext4[k++] = e; MARKLO(e); MARKLO(e->invers);
9562 	    }
9563 
9564             e = e->next;
9565             if (deg1 == deg2 && deg3 == 4)
9566             {
9567                 ext4[k++] = e; MARKLO(e); MARKLO(e->invers);
9568             }
9569 
9570             e = e->next;
9571 	    if (dega > deg1+1 || (dega == deg1+1 && deg3 == 4))
9572 	    {
9573                 ext4[k++] = e; MARKLO(e); MARKLO(e->invers);
9574 	    }
9575         }
9576     }
9577     else
9578 	deg1 = 0;
9579 
9580     for (v = 0; v < nv; ++v)
9581     if (degree[v] > deg1)
9582     {
9583 	e = elast = firstedge[v];
9584 	do
9585 	{
9586 	    if (!ISMARKEDLO(e))
9587             {
9588                 ext4[k++] = e;
9589                 MARKLO(e); MARKLO(e->invers);
9590             }
9591 	    e = e->next;
9592 	} while (e != elast);
9593     }
9594     else if (degree[v] == deg1)
9595     {
9596 	e = elast = firstedge[v];
9597         do
9598         {
9599             if (!ISMARKEDLO(e) && degree[e->end] >= deg2)
9600 	    {
9601 		ext4[k++] = e;
9602 		MARKLO(e); MARKLO(e->invers);
9603 	    }
9604             e = e->next;
9605         } while (e != elast);
9606     }
9607 
9608     if (nbtot > 1)
9609     {
9610 	nb0 = (EDGE**)numbering[0];
9611 	nblim = (EDGE**)numbering[nbtot];
9612 	for (i = 0; i < ne; ++i) nb0[i]->index = i;
9613 
9614 	kk = 0;
9615 	RESETMARKS;
9616 	for (i = 0; i < k; ++i)
9617 	if (!ISMARKEDLO(ext4[i]))
9618 	{
9619 	    ext4[kk++] = ext4[i];
9620 	    for (nb = nb0 + ext4[i]->index + MAXE; nb < nblim; nb += MAXE)
9621 	    {
9622 		MARKLO(*nb);
9623 		MARKLO((*nb)->invers);
9624 	    }
9625 	}
9626 	k = kk;
9627     }
9628 
9629     *next4 = k;
9630 }
9631 
9632 /**************************************************************************/
9633 
9634 static void
find_extensions_min4(int nbtot,int nbop,EDGE * ext4[],int * next4,EDGE * ext5[],int * next5,EDGE * extS[],int * nextS,EDGE * known)9635 find_extensions_min4(int nbtot, int nbop, EDGE *ext4[], int *next4,
9636    EDGE *ext5[], int *next5, EDGE *extS[], int *nextS, EDGE *known)
9637 
9638 /* Determine the inequivalent places to make extensions, for the
9639    ordinary triangulations of minimum degree 4.  The results are
9640    put in the arrays ext4[0..*next4-1], etc..
9641    nbtot and nbop are the usual group parameters.
9642 
9643    If known!=NULL, it is the reference edge of a known four-reduction.
9644 */
9645 {
9646     register int i,k;
9647     register EDGE *e,*e1,*elast;
9648     EDGE **nb,**nb0,**nblim,**nboplim;
9649     int manycentres;
9650 
9651     find_extensions_min4_four(nbtot,ext4,next4,known);
9652 
9653     manycentres = has_3_four_centres();
9654 
9655     if (nbtot == 1)
9656     {
9657       /* five-extensions, trivial group */
9658 
9659 	if (manycentres)
9660 	    *next5 = 0;
9661 	else if (known)
9662 	{
9663 	    k = 0;
9664 	    for (i = 0, e = known; i < 4; ++i, e = e->next)
9665 	    if (degree[e->end] >= 6)
9666 	    {
9667 		ext5[k++] = e->invers->prev->invers;
9668 		ext5[k++] = e->invers->next->next->invers;
9669 	    }
9670 	    *next5 = k;
9671 	}
9672 	else
9673 	{
9674 	    k = 0;
9675 	    for (i = 0; i < nv; ++i)
9676 	    if (degree[i] >= 6)
9677 	    {
9678 	        e = elast = firstedge[i];
9679                 do
9680                 {
9681                     ext5[k++] = e->invers;
9682                     e = e->next;
9683                 } while (e != elast);
9684             }
9685             *next5 = k;
9686 	}
9687 
9688       /* S-extensions, trivial group */
9689 
9690         k = 0;
9691 	if (nv <= maxnv-3)
9692 	{
9693             for (i = 0; i < nv; ++i)
9694             {
9695                 e = elast = firstedge[i];
9696                 do
9697                 {
9698                     e1 = e->invers->prev;
9699                     if (e1 > e)
9700                     {
9701                         e1 = e1->invers->prev;
9702                         if (e1 > e) extS[k++] = e;
9703                     }
9704                     e = e->next;
9705                 } while (e != elast);
9706             }
9707 	}
9708 	*nextS = k;
9709     }
9710     else
9711     {
9712       /* five-extensions, non-trivial group */
9713 
9714 	if (manycentres)
9715 	    *next5 = 0;
9716 	else
9717 	{
9718             nboplim = (EDGE**)numbering[nbop==0?nbtot:nbop];
9719             nblim = (EDGE**)numbering[nbtot];
9720 
9721             RESETMARKS;
9722 	    k = 0;
9723             nb0 = (EDGE**)numbering[0];
9724             for (i = 0; i < ne; ++i, ++nb0)
9725             {
9726                 e = *nb0;
9727                 if (!ISMARKEDLO(e) && degree[e->start] >= 6)
9728                 {
9729                     ext5[k++] = e->next->invers;
9730 
9731                     nb = nb0 + MAXE;
9732                     for (; nb < nboplim; nb += MAXE) MARKLO(*nb);
9733                     for (; nb < nblim; nb += MAXE) MARKLO((*nb)->prev);
9734                 }
9735             }
9736 	    *next5 = k;
9737 	}
9738 
9739       /* S-extensions, non-trivial group */
9740 
9741         k = 0;
9742 	if (nv <= maxnv-3)
9743         {
9744 	    nb0 = (EDGE**)numbering[0];
9745             nboplim = (EDGE**)numbering[nbop==0?nbtot:nbop];
9746             nblim = (EDGE**)numbering[nbtot];
9747 	    RESETMARKS;
9748 
9749 	    for (i = 0; i < ne; ++i) nb0[i]->index = i;
9750 
9751             for (i = 0; i < ne; ++i)
9752             {
9753                 e = nb0[i];
9754                 if (ISMARKEDLO(e)) continue;
9755                 extS[k++] = e;
9756 
9757                 for (nb = nb0 + i; nb < nboplim; nb += MAXE) MARKLO(*nb);
9758 
9759                 for (; nb < nblim; nb += MAXE) MARKLO((*nb)->invers);
9760 
9761                 e1 = e->invers->prev;
9762                 for (nb = nb0 + e1->index; nb < nboplim; nb += MAXE)
9763                     MARKLO(*nb);
9764 
9765                 for (; nb < nblim; nb += MAXE) MARKLO((*nb)->invers);
9766 
9767                 e1 = e1->invers->prev;
9768                 for (nb = nb0 + e1->index; nb < nboplim; nb += MAXE)
9769                     MARKLO(*nb);
9770 
9771                 for (; nb < nblim; nb += MAXE) MARKLO((*nb)->invers);
9772             }
9773 	}
9774 	*nextS = k;
9775     }
9776 }
9777 
9778 /**************************************************************************/
9779 
9780 static void
update_nft_four(triangle nft[],int numnft,EDGE * ref,triangle newnft[],int * newnumnft)9781 update_nft_four(triangle nft[], int numnft, EDGE *ref,
9782                 triangle newnft[], int *newnumnft)
9783 
9784 /* Make new list of non-facial triangles after a four-extension. */
9785 {
9786     EDGE *refmin,*e,*elast;
9787     int i,k,w;
9788 
9789     refmin = ref->min;
9790 
9791   /* Remove triangles that include ref */
9792     k = 0;
9793     for (i = 0; i < numnft; ++i)
9794         if (nft[i].e1 != refmin && nft[i].e2 != refmin && nft[i].e3 != refmin)
9795             newnft[k++] = nft[i];
9796 
9797   /* Add a shortcut if there is one (only possible if there are >= 2 others) */
9798     if (k >= 2)
9799     {
9800         w = ref->next->end;
9801         elast = ref->invers->next->invers;
9802         for (e = elast->next->next->next; e != elast; e = e->next)
9803             if (e->end == w) break;
9804         if (e != elast)
9805         {
9806             newnft[k].e1 = e->min;
9807             newnft[k].e2 = ref->prev->min;
9808             newnft[k].e3 = ref->next->min;
9809             ++k;
9810         }
9811     }
9812     *newnumnft = k;
9813 }
9814 
9815 /**************************************************************************/
9816 
9817 static void
update_nft_five(triangle nft[],int numnft,EDGE * ref,triangle newnft[],int * newnumnft)9818 update_nft_five(triangle nft[], int numnft, EDGE *ref,
9819                 triangle newnft[], int *newnumnft)
9820 
9821 /* Make new list of non-facial triangles after a five-extension. */
9822 {
9823     EDGE *refmin,*amin,*e,*elast,*ee;
9824     int i,k,w,j;
9825 
9826     refmin = ref->min;
9827     amin = ref->next->next->min;
9828 
9829   /* Remove triangles that include either of the former two chords */
9830     k = 0;
9831     for (i = 0; i < numnft; ++i)
9832         if (nft[i].e1 != refmin && nft[i].e2 != refmin && nft[i].e3 != refmin
9833                 && nft[i].e1 != amin && nft[i].e2 != amin && nft[i].e3 != amin)
9834             newnft[k++] = nft[i];
9835 
9836   /* Add a shortcut if there is one (only possible if there is another) */
9837 
9838     if (k == 0)
9839     {
9840         *newnumnft = 0;
9841         return;
9842     }
9843 
9844     for (ee = ref->prev->prev, j = 0; j < 3; ee = ee->next->next, ++j)
9845     {
9846         w = ee->next->end;
9847         elast = ee->invers->next->invers;
9848         for (e = elast->next->next->next; e != elast; e = e->next)
9849             if (e->end == w) break;
9850         if (e != elast)
9851         {
9852             newnft[k].e1 = e->min;
9853             newnft[k].e2 = ee->prev->min;
9854             newnft[k].e3 = ee->next->min;
9855             ++k;
9856         }
9857     }
9858     *newnumnft = k;
9859 }
9860 
9861 /**************************************************************************/
9862 
9863 static void
nftlaststep(EDGE * ext4[],int * next4,EDGE * ext5[],int * next5,triangle nft[],int numnft)9864 nftlaststep(EDGE *ext4[], int *next4, EDGE *ext5[], int *next5,
9865             triangle nft[], int numnft)
9866 
9867 /* Remove from ext4[0..*next4-1] and ext5[0..*next5-1] those extensions
9868    for which not all of nft[0..numnft-1] hit some chord. */
9869 {
9870     int i,j,k;
9871 
9872     for (j = 0; j < numnft; ++j)
9873     {
9874         RESETMARKS;
9875         MARKLO(nft[j].e1); MARKLO(nft[j].e1->invers);
9876         MARKLO(nft[j].e2); MARKLO(nft[j].e2->invers);
9877         MARKLO(nft[j].e3); MARKLO(nft[j].e3->invers);
9878 
9879         k = 0;
9880         for (i = 0; i < *next4; ++i)
9881             if (ISMARKEDLO(ext4[i])) ext4[k++] = ext4[i];
9882         *next4 = k;
9883 
9884         k = 0;
9885         for (i = 0; i < *next5; ++i)
9886             if (ISMARKEDLO(ext5[i]) || ISMARKEDLO(ext5[i]->invers->prev))
9887                 ext5[k++] = ext5[i];
9888         *next5 = k;
9889     }
9890 }
9891 
9892 /**************************************************************************/
9893 
9894 static void
scanmin4c(int nbtot,int nbop,int dosplit,EDGE * lastfour,triangle nft[],int numnft)9895 scanmin4c(int nbtot, int nbop, int dosplit, EDGE *lastfour,
9896           triangle nft[], int numnft)
9897 
9898 /* The main node of the recursion for triangulations with minimum
9899    degree at least 4.  This is the version keeping track of all the
9900    non-facial triangles.
9901    As this procedure is entered, nv,ne,degree etc are set for some graph,
9902    and nbtot/nbop are the values returned by canon() for that graph.
9903    If dosplit==TRUE, this is the place to do splitting (if any).
9904    Splitting is a bit more complicated because the S operation adds
9905    three vertices.
9906    If this graph was made with a four-operation, the reference edge of
9907    that operation is lastfour.  If not, lastfour=NULL.
9908    nft[0..numnft-1] is a list of all the non-facial triangles.
9909    Edges in the triangles must be in min form.
9910 */
9911 {
9912     EDGE *firstedge_save[MAXN];
9913     EDGE *ext4[MAXE/2],*ext5[MAXE],*extS[MAXF];
9914     EDGE *good_or[MAXE],*good_mir[MAXE],*e;
9915     triangle newnft[MAXN];
9916     int newnumnft;
9917     int ngood_or,ngood_mir,ngood_ref,ngood_mir_ref;
9918     int next4,next5,nextS,i;
9919     int xnbtot,xnbop;
9920     int hint;
9921 
9922     if (nv == maxnv)
9923     {
9924 	if (numnft == 0)
9925         {
9926 	    if (pswitch) startpolyscan(nbtot,nbop);
9927             else         got_one(nbtot,nbop,4);
9928         }
9929 	else if (xswitch)
9930 	    got_one(nbtot,nbop,3);
9931         return;
9932     }
9933 
9934     if (dosplit)
9935     {
9936 #ifdef SPLITTEST
9937         ++splitcases;
9938         return;
9939 #endif
9940         if (splitcount-- != 0) return;
9941         splitcount = mod - 1;
9942 
9943         for (i = 0; i < nv; ++i) firstedge_save[i] = firstedge[i];
9944     }
9945 
9946 #ifdef PRE_FILTER_MIN4
9947     if (!(PRE_FILTER_MIN4)) return;
9948 #endif
9949 
9950 #ifndef FIND_EXTENSIONS_MIN4
9951 #define FIND_EXTENSIONS_MIN4 find_extensions_min4
9952 #endif
9953 
9954     FIND_EXTENSIONS_MIN4(nbtot,nbop,ext4,&next4,ext5,&next5,extS,&nextS,
9955                          lastfour);
9956 
9957     if (nv == maxnv-1 && numnft > 0 && minconnec == 4) /* rules out m4c3x */
9958         nftlaststep(ext4,&next4,ext5,&next5,nft,numnft);
9959 
9960     for (i = 0; i < next4; ++i)
9961     {
9962         extend_four(ext4[i]);
9963 #ifdef FAST_FILTER_MIN4
9964         if (FAST_FILTER_MIN4)
9965 #endif
9966         {
9967             min4_four_legal(ext4[i],good_or,&ngood_or,&ngood_ref,
9968                          good_mir,&ngood_mir,&ngood_mir_ref);
9969 
9970             if (ngood_ref+ngood_mir_ref > 0)
9971             {
9972                 if (nv == maxnv && !needgroup && ngood_or == ngood_ref
9973                                                 && ngood_mir == ngood_mir_ref)
9974                 {
9975                     update_nft_four(nft,numnft,ext4[i],newnft,&newnumnft);
9976                     got_one(1,1,3+(newnumnft==0));
9977                 }
9978                 else if (ngood_or+ngood_mir==1)
9979                 {
9980                     update_nft_four(nft,numnft,ext4[i],newnft,&newnumnft);
9981                     scanmin4c(1,1,nv==splitlevel,ext4[i],newnft,newnumnft);
9982                 }
9983                 else if (canon_edge_oriented(good_or,ngood_or,ngood_ref,
9984                                            good_mir,ngood_mir,ngood_mir_ref,
9985                                            degree,numbering,&xnbtot,&xnbop))
9986                 {
9987                     update_nft_four(nft,numnft,ext4[i],newnft,&newnumnft);
9988                     scanmin4c(xnbtot,xnbop,nv==splitlevel,ext4[i],
9989                              newnft,newnumnft);
9990                 }
9991             }
9992         }
9993         reduce_four(ext4[i]);
9994     }
9995 
9996     hint = -1;
9997     for (i = 0; i < next5; ++i)
9998     {
9999         extend_five(ext5[i]);
10000 #ifdef FAST_FILTER_MIN4
10001         if (FAST_FILTER_MIN4)
10002 #endif
10003         {
10004             if (hint < 0 || !is_min4_four_centre(hint))
10005                 hint = min4_four_centre();
10006             if (hint < 0)
10007             {
10008                 min4_five_legal(ext5[i],good_or,&ngood_or,&ngood_ref,
10009                              good_mir,&ngood_mir,&ngood_mir_ref);
10010                 if (ngood_ref+ngood_mir_ref > 0)
10011                 {
10012                     if (canon_edge_oriented(good_or,ngood_or,ngood_ref,
10013                                             good_mir,ngood_mir,ngood_mir_ref,
10014                                             degree,numbering,&xnbtot,&xnbop))
10015                     {
10016                         update_nft_five(nft,numnft,ext5[i],newnft,&newnumnft);
10017                         scanmin4c(xnbtot,xnbop,nv==splitlevel,NULL,
10018                                  newnft,newnumnft);
10019                     }
10020                 }
10021             }
10022 	}
10023         reduce_five(ext5[i]);
10024     }
10025 
10026     for (i = 0; i < nextS; ++i)
10027     {
10028         extend_S(extS[i]);
10029 #ifdef FAST_FILTER_MIN4
10030         if (FAST_FILTER_MIN4)
10031 #endif
10032         {
10033             if (degree5_vertex() < 0 && min4_four_centre() < 0)
10034             {
10035                 min4_S_legal(extS[i],good_or,&ngood_or,&ngood_ref,
10036                              good_mir,&ngood_mir,&ngood_mir_ref);
10037                 if (ngood_ref+ngood_mir_ref > 0)
10038                 {
10039                     if (canon_edge_oriented(good_or,ngood_or,ngood_ref,
10040                                             good_mir,ngood_mir,ngood_mir_ref,
10041                                             zero,numbering,&xnbtot,&xnbop))
10042                     {
10043                         e = extS[i];
10044                         nft[numnft].e1 = e->min;
10045                         e = e->invers->prev->prev->prev;
10046                         nft[numnft].e2 = e->min;
10047                         e = e->invers->prev->prev->prev;
10048                         nft[numnft].e3 = e->min;
10049                         scanmin4c(xnbtot,xnbop,
10050 			   nv>=splitlevel&&nv<=splitlevel+2,NULL,nft,numnft+1);
10051                     }
10052                 }
10053             }
10054         }
10055         reduce_S(extS[i]);
10056     }
10057 
10058     if (dosplit)
10059         for (i = 0; i < nv; ++i) firstedge[i] = firstedge_save[i];
10060 }
10061 
10062 /**************************************************************************/
10063 
10064 static void
scanmin4(int nbtot,int nbop,int dosplit,EDGE * lastfour)10065 scanmin4(int nbtot, int nbop, int dosplit, EDGE *lastfour)
10066 
10067 /* The main node of the recursion for triangulations with minimum
10068    degree at least 4.
10069    As this procedure is entered, nv,ne,degree etc are set for some graph,
10070    and nbtot/nbop are the values returned by canon() for that graph.
10071    If dosplit==TRUE, this is the place to do splitting (if any).
10072    Splitting is a bit more complicated because the S operation adds
10073    three vertices.
10074    If this graph was made with a four-operation, the reference edge of
10075    that operation is lastfour.  If not, lastfour=NULL.
10076 */
10077 {
10078     EDGE *firstedge_save[MAXN];
10079     EDGE *ext4[MAXE/2],*ext5[MAXE],*extS[MAXF];
10080     EDGE *good_or[MAXE],*good_mir[MAXE];
10081     int ngood_or,ngood_mir,ngood_ref,ngood_mir_ref;
10082     int next4,next5,nextS,i;
10083     int xnbtot,xnbop;
10084     int hint;
10085 
10086     if (nv == maxnv)
10087     {
10088         if (pswitch) startpolyscan(nbtot,nbop);
10089 	else         got_one(nbtot,nbop,3);
10090 	return;
10091     }
10092 
10093     if (dosplit)
10094     {
10095 #ifdef SPLITTEST
10096         ++splitcases;
10097         return;
10098 #endif
10099         if (splitcount-- != 0) return;
10100         splitcount = mod - 1;
10101 
10102         for (i = 0; i < nv; ++i) firstedge_save[i] = firstedge[i];
10103     }
10104 
10105 #ifdef PRE_FILTER_MIN4
10106     if (!(PRE_FILTER_MIN4)) return;
10107 #endif
10108 
10109 #ifndef FIND_EXTENSIONS_MIN4
10110 #define FIND_EXTENSIONS_MIN4 find_extensions_min4
10111 #endif
10112 
10113     FIND_EXTENSIONS_MIN4(nbtot,nbop,ext4,&next4,ext5,&next5,extS,&nextS,
10114 			 lastfour);
10115 
10116     for (i = 0; i < next4; ++i)
10117     {
10118         extend_four(ext4[i]);
10119 #ifdef FAST_FILTER_MIN4
10120         if (FAST_FILTER_MIN4)
10121 #endif
10122         {
10123 	    min4_four_legal(ext4[i],good_or,&ngood_or,&ngood_ref,
10124 		         good_mir,&ngood_mir,&ngood_mir_ref);
10125 
10126             if (ngood_ref+ngood_mir_ref > 0)
10127 	    {
10128 	        if (nv == maxnv && !needgroup && ngood_or == ngood_ref
10129                                                 && ngood_mir == ngood_mir_ref)
10130 		    got_one(1,1,3);
10131 	        else if (ngood_or+ngood_mir==1)
10132     		    scanmin4(1,1,nv==splitlevel,ext4[i]);
10133 	        else if (canon_edge_oriented(good_or,ngood_or,ngood_ref,
10134                                            good_mir,ngood_mir,ngood_mir_ref,
10135                                            degree,numbering,&xnbtot,&xnbop))
10136 	            scanmin4(xnbtot,xnbop,nv==splitlevel,ext4[i]);
10137 	    }
10138 	}
10139 	reduce_four(ext4[i]);
10140     }
10141 
10142     /* hint = lastfour ? lastfour->start : -1; */
10143     hint = -1;
10144     for (i = 0; i < next5; ++i)
10145     {
10146         extend_five(ext5[i]);
10147 #ifdef FAST_FILTER_MIN4
10148         if (FAST_FILTER_MIN4)
10149 #endif
10150         {
10151             if (hint < 0 || !is_min4_four_centre(hint))
10152 	        hint = min4_four_centre();
10153 	    if (hint < 0)
10154 	    {
10155                 min4_five_legal(ext5[i],good_or,&ngood_or,&ngood_ref,
10156                                 good_mir,&ngood_mir,&ngood_mir_ref);
10157                 if (ngood_ref+ngood_mir_ref > 0)
10158                 {
10159                     if (canon_edge_oriented(good_or,ngood_or,ngood_ref,
10160                                             good_mir,ngood_mir,ngood_mir_ref,
10161                                             degree,numbering,&xnbtot,&xnbop))
10162                     scanmin4(xnbtot,xnbop,nv==splitlevel,NULL);
10163                 }
10164 	    }
10165 	}
10166         reduce_five(ext5[i]);
10167     }
10168 
10169     for (i = 0; i < nextS; ++i)
10170     {
10171         extend_S(extS[i]);
10172 #ifdef FAST_FILTER_MIN4
10173         if (FAST_FILTER_MIN4)
10174 #endif
10175         {
10176             if (degree5_vertex() < 0 && min4_four_centre() < 0)
10177             {
10178                 min4_S_legal(extS[i],good_or,&ngood_or,&ngood_ref,
10179                              good_mir,&ngood_mir,&ngood_mir_ref);
10180                 if (ngood_ref+ngood_mir_ref > 0)
10181                 {
10182                     if (canon_edge_oriented(good_or,ngood_or,ngood_ref,
10183                                             good_mir,ngood_mir,ngood_mir_ref,
10184                                             zero,numbering,&xnbtot,&xnbop))
10185                     scanmin4(xnbtot,xnbop,
10186 			     nv>=splitlevel&&nv<=splitlevel+2,NULL);
10187                     }
10188             }
10189         }
10190         reduce_S(extS[i]);
10191     }
10192 
10193     if (dosplit)
10194         for (i = 0; i < nv; ++i) firstedge[i] = firstedge_save[i];
10195 }
10196 
10197 /**************************************************************************/
10198 
10199 static EDGE*
extend_min5_a(EDGE * e1,EDGE * e2)10200 extend_min5_a(EDGE *e1, EDGE *e2)
10201 
10202 /* extends a graph in the way given by the type a extension for
10203    5-connected triangulations. The edges e1, e2 start at the same
10204    vertex and must have at least two edges on each of their sides.
10205 
10206    It returns the edge characterizing this operation.
10207 */
10208 
10209 {
10210   register EDGE *e3, *e4, *start, *run, *e1i, *e2i, *work1, *work2;
10211   int end1, end2, center, counter;
10212 
10213   e3=e1->next;
10214   e4=e2->prev;
10215   e1i=e1->invers;
10216   e2i=e2->invers;
10217   work1=e1i->prev;
10218   work2=e2i->next;
10219   center=e1->start;
10220   end1=e1->end;
10221   end2=e2->end;
10222 
10223   start=min5_a(nv);
10224   firstedge[center]=start+2;
10225   firstedge[nv]=start+1;
10226 
10227   counter=1; run=e3; run->start=run->invers->end=nv;
10228   do { run=run->next; run->start=run->invers->end=nv; counter++; }
10229   while (run != e4);
10230 
10231   degree[nv]=counter+3;
10232   degree[center]-=(counter-1);
10233 
10234   start->start=end1;
10235   start->prev=work1;
10236   start->next=e1i;
10237   work1->next=e1i->prev=start;
10238   (degree[end1])++;
10239 
10240   run=start+1;
10241   run->end=end1;
10242   run->next=e3;
10243   e3->prev=run;
10244 
10245   run++; /*start+2*/
10246   run->start=center;
10247   run->next=e2;
10248   run->prev=e1;
10249   e1->next=e2->prev=run;
10250 
10251   run++; /*start+3*/
10252   run->end=center;
10253 
10254   run++; /*start+4*/
10255   run->start=end2;
10256   run->prev=e2i;
10257   run->next=work2;
10258   e2i->next=work2->prev=run;
10259   (degree[end2])++;
10260 
10261   run++; /*start+5*/
10262   run->end=end2;
10263   run->prev=e4;
10264   e4->next=run;
10265 
10266   nv++; ne+=6;
10267 
10268   return (start+2); /* It is the minimum of the two inverse edges */
10269 }
10270 
10271 /**************************************************************************/
10272 
10273 static void
reduce_min5_a(EDGE * e)10274 reduce_min5_a(EDGE *e)
10275 
10276 /* reduces the graph previously extended by the type a extension for
10277    5-connected triangulations if the edge returned by the function is
10278    given as a parameter.
10279 */
10280 
10281 {
10282   register EDGE *e1, *e2, *e3, *e4, *e1i, *e2i, *work1, *work2, *run;
10283   int end1, end2, center, counter;
10284 
10285   e1=e->prev;
10286   e2=e->next;
10287   e1i=e1->invers;
10288   e2i=e2->invers;
10289   work1=e1i->prev->prev;
10290   work2=e2i->next->next;
10291 
10292   e=e->invers;
10293   e3=e->next->next;
10294   e4=e->prev->prev;
10295   center=e1->start;
10296   end1=e1->end;
10297   end2=e2->end;
10298 
10299   firstedge[center]=e1;
10300   firstedge[end1]=e1i;
10301   firstedge[end2]=e2i;
10302 
10303   counter=1; run=e3; run->start=run->invers->end=center;
10304   do { run=run->next; run->start=run->invers->end=center; counter++; }
10305   while (run != e4);
10306 
10307   degree[center]+=(counter-1);
10308   degree[end1]--;
10309   degree[end2]--;
10310 
10311   e1->next=e3; e3->prev=e1;
10312   e2->prev=e4; e4->next=e2;
10313 
10314   e1i->prev=work1; work1->next=e1i;
10315   e2i->next=work2; work2->prev=e2i;
10316 
10317   nv--; ne-=6;
10318 
10319 }
10320 
10321 /**************************************************************************/
10322 
10323 static EDGE*
extend_min5_b(EDGE * e,int do_mirror)10324 extend_min5_b(EDGE *e, int do_mirror)
10325 
10326 /* extends a graph in the way given by the type b extension for
10327    5-connected triangulations. The edge e must start and end at
10328    a vertex of degree 5.
10329 
10330    It returns the edge characterizing this operation.
10331 
10332 */
10333 
10334 {
10335 
10336   EDGE *ei, *e2, *e2i, *e3, *e3i, *e4, *e5i;
10337   EDGE *start, *run, *work1, *work2, *work3;
10338   int end2, center1, center2, start3;
10339 
10340 
10341 if (!do_mirror)
10342   {
10343   ei=e->invers;
10344   work2=e->next;
10345   work3=work2->next;
10346   e3i=work3->next;
10347   e3=e3i->invers;
10348   e5i=e3->next;
10349   work1=ei->prev;
10350   e2=work1->prev;
10351   e2i=e2->invers;
10352   e4=e2i->prev;
10353 
10354   center1=e->end;
10355   center2=e->start;
10356   start3=e3->start;
10357   end2=e2->end;
10358 
10359   start=min5_b0(nv);
10360 
10361   work1->start=work1->invers->end=nv;
10362   firstedge[nv]=work1;
10363   degree[nv]=5;
10364 
10365   work2->start=work2->invers->end=work3->start=work3->invers->end=nv+1;
10366   firstedge[nv+1]=work2;
10367   degree[nv+1]=5;
10368 
10369   firstedge[center1]=ei;
10370   firstedge[center2]=e;
10371 
10372   /* The degree at center1 and center2 remains unchanged */
10373 
10374 
10375   start->start=end2;
10376   start->prev=e4; e4->next=start;
10377   start->next=e2i; e2i->prev=start;
10378   (degree[end2])++;
10379 
10380   run=start+1;
10381   run->end=end2; run->next=work1; work1->prev=run;
10382 
10383   run++; /*2*/
10384   run->start=(run+1)->end=center1;
10385   run->prev=e2; e2->next=run;
10386   run->next=ei; ei->prev=run;
10387 
10388   run+=2; /*4*/
10389   run->start=(run+1)->end=center2;
10390   run->prev=e; e->next=run;
10391 
10392   run+=2; /*6*/
10393   run->next=work2; work2->prev=run;
10394 
10395   run++; /*7*/
10396   run->prev=work1; work1->next=run;
10397 
10398   run++; /*8*/
10399   run->start=(run+1)->end=center2;
10400   run->next=e3i; e3i->prev=run;
10401 
10402   run+=2; /*10*/
10403   run->start=start3;
10404   run->next=e5i; e5i->prev=run;
10405   run->prev=e3; e3->next=run;
10406 
10407   run++; /*11*/
10408   run->end=start3;
10409   run->prev=work3; work3->next=run;
10410   degree[start3]++;
10411 
10412   nv+=2; ne+=12;
10413 
10414   return (start+4); /* is the smaller one */
10415   }
10416 
10417  else /* do_mirror=1*/
10418   {
10419   ei=e->invers;
10420   work2=e->prev;
10421   work3=work2->prev;
10422   e3i=work3->prev;
10423   e3=e3i->invers;
10424   e5i=e3->prev;
10425   work1=ei->next;
10426   e2=work1->next;
10427   e2i=e2->invers;
10428   e4=e2i->next;
10429 
10430   center1=e->end;
10431   center2=e->start;
10432   start3=e3->start;
10433   end2=e2->end;
10434 
10435   start=min5_b1(nv);
10436 
10437   work1->start=work1->invers->end=nv;
10438   firstedge[nv]=work1;
10439   degree[nv]=5;
10440 
10441   work2->start=work2->invers->end=work3->start=work3->invers->end=nv+1;
10442   firstedge[nv+1]=work2;
10443   degree[nv+1]=5;
10444 
10445   firstedge[center1]=ei;
10446   firstedge[center2]=e;
10447 
10448   /* The degree at center1 and center2 remains unchanged */
10449 
10450 
10451   start->start=end2;
10452   start->next=e4; e4->prev=start;
10453   start->prev=e2i; e2i->next=start;
10454   (degree[end2])++;
10455 
10456   run=start+1;
10457   run->end=end2; run->prev=work1; work1->next=run;
10458 
10459   run++; /*2*/
10460   run->start=(run+1)->end=center1;
10461   run->next=e2; e2->prev=run;
10462   run->prev=ei; ei->next=run;
10463 
10464   run+=2; /*4*/
10465   run->start=(run+1)->end=center2;
10466   run->next=e; e->prev=run;
10467 
10468   run+=2; /*6*/
10469   run->prev=work2; work2->next=run;
10470 
10471   run++; /*7*/
10472   run->next=work1; work1->prev=run;
10473 
10474   run++; /*8*/
10475   run->start=(run+1)->end=center2;
10476   run->prev=e3i; e3i->next=run;
10477 
10478   run+=2; /*10*/
10479   run->start=start3;
10480   run->prev=e5i; e5i->next=run;
10481   run->next=e3; e3->prev=run;
10482 
10483   run++; /*11*/
10484   run->end=start3;
10485   run->next=work3; work3->prev=run;
10486   degree[start3]++;
10487 
10488   nv+=2; ne+=12;
10489 
10490   return (start+4); /* is the smaller one */
10491   }
10492 
10493 }
10494 
10495 /**************************************************************************/
10496 
10497 static void
reduce_min5_b(EDGE * ref,int do_mirror)10498 reduce_min5_b(EDGE *ref, int do_mirror)
10499 
10500 {
10501   EDGE *e, *ei, *e2, *e2i, *e4, *work1, *work2, *work3, *e3, *e3i, *e5i;
10502   int center1, center2, end2, start3;
10503 
10504 
10505 if (!do_mirror)
10506    {
10507      e=ref->prev;
10508      ei=e->invers;
10509      e2=ei->prev->prev;
10510      e2i=e2->invers;
10511      e4=e2i->prev->prev;
10512      work1=e4->next->invers->next;
10513      e3i=e->prev->prev;
10514      e3=e3i->invers;
10515      e5i=e3->next->next;
10516      work3=e5i->prev->invers->prev;
10517      work2=work3->prev;
10518 
10519      end2=e2->end;
10520      center1=e->end;
10521      center2=e->start;
10522      start3=e3->start;
10523 
10524      degree[end2]--;
10525      degree[start3]--;
10526 
10527      firstedge[end2]=e4;
10528      firstedge[center1]=ei;
10529      firstedge[center2]=e;
10530      firstedge[start3]=e3;
10531 
10532      e4->next=e2i; e2i->prev=e4;
10533      e2->next=work1; work1->prev=e2;
10534      ei->prev=work1; work1->next=ei;
10535      e->next=work2; work2->prev=e;
10536      e3i->prev=work3; work3->next=e3i;
10537      e3->next=e5i; e5i->prev=e3;
10538 
10539      work1->start=work1->invers->end=center1;
10540      work2->start=work2->invers->end=work3->start=work3->invers->end=center2;
10541 
10542      nv-=2; ne-=12;
10543    }
10544 
10545 else
10546    {
10547      e=ref->next;
10548      ei=e->invers;
10549      e2=ei->next->next;
10550      e2i=e2->invers;
10551      e4=e2i->next->next;
10552      work1=e4->prev->invers->prev;
10553      e3i=e->next->next;
10554      e3=e3i->invers;
10555      e5i=e3->prev->prev;
10556      work3=e5i->next->invers->next;
10557      work2=work3->next;
10558 
10559      end2=e2->end;
10560      center1=e->end;
10561      center2=e->start;
10562      start3=e3->start;
10563 
10564      degree[end2]--;
10565      degree[start3]--;
10566 
10567      firstedge[end2]=e4;
10568      firstedge[center1]=ei;
10569      firstedge[center2]=e;
10570      firstedge[start3]=e3;
10571 
10572      e4->prev=e2i; e2i->next=e4;
10573      e2->prev=work1; work1->next=e2;
10574      ei->next=work1; work1->prev=ei;
10575      e->prev=work2; work2->next=e;
10576      e3i->next=work3; work3->prev=e3i;
10577      e3->prev=e5i; e5i->next=e3;
10578 
10579      work1->start=work1->invers->end=center1;
10580      work2->start=work2->invers->end=work3->start=work3->invers->end=center2;
10581 
10582      nv-=2; ne-=12;
10583    }
10584 
10585 }
10586 
10587 /**************************************************************************/
10588 
10589 static void
make_icosahedron(void)10590 make_icosahedron(void)
10591 
10592 /* Make an icosahedron using the first 60 edges */
10593 {
10594    int i;
10595    EDGE *buffer;
10596 
10597     for (i=0; i<=11; i++)
10598       { buffer=edges+5*i;
10599         firstedge[i]=buffer; degree[i]=5;
10600         buffer->next=buffer+1; buffer->prev=buffer+4; buffer->start=i;
10601         buffer++; buffer->next=buffer+1; buffer->prev=buffer-1; buffer->start=i;
10602         buffer++; buffer->next=buffer+1; buffer->prev=buffer-1; buffer->start=i;
10603 	buffer++; buffer->next=buffer+1; buffer->prev=buffer-1; buffer->start=i;
10604         buffer++; buffer->next=buffer-4; buffer->prev=buffer-1; buffer->start=i;
10605       }
10606 
10607     buffer=edges; /* edge number 0 */
10608     buffer->end=1;
10609     buffer->invers=edges+5;
10610     buffer->min=buffer;
10611 
10612     buffer++; /* edge number 1 */
10613     buffer->end=2;
10614     buffer->invers=edges+10;
10615     buffer->min=buffer;
10616 
10617     buffer++; /* edge number 2 */
10618     buffer->end=3;
10619     buffer->invers=edges+15;
10620     buffer->min=buffer;
10621 
10622     buffer++; /* edge number 3 */
10623     buffer->end=4;
10624     buffer->invers=edges+20;
10625     buffer->min=buffer;
10626 
10627     buffer++; /* edge number 4 */
10628     buffer->end=5;
10629     buffer->invers=edges+25;
10630     buffer->min=buffer;
10631 
10632     buffer++; /* edge number 5 */
10633     buffer->end=0;
10634     buffer->invers=edges;
10635     buffer->min=buffer->invers;
10636 
10637     buffer++; /* edge number 6 */
10638     buffer->end=5;
10639     buffer->invers=edges+29;
10640     buffer->min=buffer;
10641 
10642     buffer++; /* edge number 7 */
10643     buffer->end=6;
10644     buffer->invers=edges+30;
10645     buffer->min=buffer;
10646 
10647     buffer++; /* edge number 8 */
10648     buffer->end=7;
10649     buffer->invers=edges+35;
10650     buffer->min=buffer;
10651 
10652     buffer++; /* edge number 9 */
10653     buffer->end=2;
10654     buffer->invers=edges+11;
10655     buffer->min=buffer;
10656 
10657     buffer++; /* edge number 10 */
10658     buffer->end=0;
10659     buffer->invers=edges+1;
10660     buffer->min=buffer->invers;
10661 
10662     buffer++; /* edge number 11 */
10663     buffer->end=1;
10664     buffer->invers=edges+9;
10665     buffer->min=buffer->invers;
10666 
10667     buffer++; /* edge number 12 */
10668     buffer->end=7;
10669     buffer->invers=edges+39;
10670     buffer->min=buffer;
10671 
10672     buffer++; /* edge number 13 */
10673     buffer->end=8;
10674     buffer->invers=edges+40;
10675     buffer->min=buffer;
10676 
10677     buffer++; /* edge number 14 */
10678     buffer->end=3;
10679     buffer->invers=edges+16;
10680     buffer->min=buffer;
10681 
10682     buffer++; /* edge number 15 */
10683     buffer->end=0;
10684     buffer->invers=edges+2;
10685     buffer->min=buffer->invers;
10686 
10687     buffer++; /* edge number 16 */
10688     buffer->end=2;
10689     buffer->invers=edges+14;
10690     buffer->min=buffer->invers;
10691 
10692     buffer++; /* edge number 17 */
10693     buffer->end=8;
10694     buffer->invers=edges+44;
10695     buffer->min=buffer;
10696 
10697     buffer++; /* edge number 18 */
10698     buffer->end=9;
10699     buffer->invers=edges+45;
10700     buffer->min=buffer;
10701 
10702     buffer++; /* edge number 19  */
10703     buffer->end=4;
10704     buffer->invers=edges+21;
10705     buffer->min=buffer;
10706 
10707     buffer++; /* edge number 20 */
10708     buffer->end=0;
10709     buffer->invers=edges+3;
10710     buffer->min=buffer->invers;
10711 
10712     buffer++; /* edge number 21 */
10713     buffer->end=3;
10714     buffer->invers=edges+19;
10715     buffer->min=buffer->invers;
10716 
10717     buffer++; /* edge number 22 */
10718     buffer->end=9;
10719     buffer->invers=edges+49;
10720     buffer->min=buffer;
10721 
10722     buffer++; /* edge number 23 */
10723     buffer->end=10;
10724     buffer->invers=edges+50;
10725     buffer->min=buffer;
10726 
10727     buffer++; /* edge number 24 */
10728     buffer->end=5;
10729     buffer->invers=edges+26;
10730     buffer->min=buffer;
10731 
10732     buffer++; /* edge number 25 */
10733     buffer->end=0;
10734     buffer->invers=edges+4;
10735     buffer->min=buffer->invers;
10736 
10737     buffer++; /* edge number 26 */
10738     buffer->end=4;
10739     buffer->invers=edges+24;
10740     buffer->min=buffer->invers;
10741 
10742     buffer++; /* edge number 27 */
10743     buffer->end=10;
10744     buffer->invers=edges+54;
10745     buffer->min=buffer;
10746 
10747     buffer++; /* edge number 28 */
10748     buffer->end=6;
10749     buffer->invers=edges+31;
10750     buffer->min=buffer;
10751 
10752     buffer++; /* edge number 29  */
10753     buffer->end=1;
10754     buffer->invers=edges+6;
10755     buffer->min=buffer->invers;
10756 
10757     buffer++; /* edge number 30 */
10758     buffer->end=1;
10759     buffer->invers=edges+7;
10760     buffer->min=buffer->invers;
10761 
10762     buffer++; /* edge number 31 */
10763     buffer->end=5;
10764     buffer->invers=edges+28;
10765     buffer->min=buffer->invers;
10766 
10767     buffer++; /* edge number 32 */
10768     buffer->end=10;
10769     buffer->invers=edges+53;
10770     buffer->min=buffer;
10771 
10772     buffer++; /* edge number 33 */
10773     buffer->end=11;
10774     buffer->invers=edges+55;
10775     buffer->min=buffer;
10776 
10777     buffer++; /* edge number 34 */
10778     buffer->end=7;
10779     buffer->invers=edges+36;
10780     buffer->min=buffer;
10781 
10782     buffer++; /* edge number 35 */
10783     buffer->end=1;
10784     buffer->invers=edges+8;
10785     buffer->min=buffer->invers;
10786 
10787     buffer++; /* edge number 36 */
10788     buffer->end=6;
10789     buffer->invers=edges+34;
10790     buffer->min=buffer->invers;
10791 
10792     buffer++; /* edge number 37 */
10793     buffer->end=11;
10794     buffer->invers=edges+59;
10795     buffer->min=buffer;
10796 
10797     buffer++; /* edge number 38 */
10798     buffer->end=8;
10799     buffer->invers=edges+41;
10800     buffer->min=buffer;
10801 
10802     buffer++; /* edge number 39  */
10803     buffer->end=2;
10804     buffer->invers=edges+12;
10805     buffer->min=buffer->invers;
10806 
10807     buffer++; /* edge number 40 */
10808     buffer->end=2;
10809     buffer->invers=edges+13;
10810     buffer->min=buffer->invers;
10811 
10812     buffer++; /* edge number 41 */
10813     buffer->end=7;
10814     buffer->invers=edges+38;
10815     buffer->min=buffer->invers;
10816 
10817     buffer++; /* edge number 42 */
10818     buffer->end=11;
10819     buffer->invers=edges+58;
10820     buffer->min=buffer;
10821 
10822     buffer++; /* edge number 43 */
10823     buffer->end=9;
10824     buffer->invers=edges+46;
10825     buffer->min=buffer;
10826 
10827     buffer++; /* edge number 44 */
10828     buffer->end=3;
10829     buffer->invers=edges+17;
10830     buffer->min=buffer->invers;
10831 
10832     buffer++; /* edge number 45 */
10833     buffer->end=3;
10834     buffer->invers=edges+18;
10835     buffer->min=buffer->invers;
10836 
10837     buffer++; /* edge number 46 */
10838     buffer->end=8;
10839     buffer->invers=edges+43;
10840     buffer->min=buffer->invers;
10841 
10842     buffer++; /* edge number 47 */
10843     buffer->end=11;
10844     buffer->invers=edges+57;
10845     buffer->min=buffer;
10846 
10847     buffer++; /* edge number 48 */
10848     buffer->end=10;
10849     buffer->invers=edges+51;
10850     buffer->min=buffer;
10851 
10852     buffer++; /* edge number 49  */
10853     buffer->end=4;
10854     buffer->invers=edges+22;
10855     buffer->min=buffer->invers;
10856 
10857     buffer++; /* edge number 50 */
10858     buffer->end=4;
10859     buffer->invers=edges+23;
10860     buffer->min=buffer->invers;
10861 
10862     buffer++; /* edge number 51 */
10863     buffer->end=9;
10864     buffer->invers=edges+48;
10865     buffer->min=buffer->invers;
10866 
10867     buffer++; /* edge number 52 */
10868     buffer->end=11;
10869     buffer->invers=edges+56;
10870     buffer->min=buffer;
10871 
10872     buffer++; /* edge number 53 */
10873     buffer->end=6;
10874     buffer->invers=edges+32;
10875     buffer->min=buffer->invers;
10876 
10877     buffer++; /* edge number 54 */
10878     buffer->end=5;
10879     buffer->invers=edges+27;
10880     buffer->min=buffer->invers;
10881 
10882     buffer++; /* edge number 55 */
10883     buffer->end=6;
10884     buffer->invers=edges+33;
10885     buffer->min=buffer->invers;
10886 
10887     buffer++; /* edge number 56 */
10888     buffer->end=10;
10889     buffer->invers=edges+52;
10890     buffer->min=buffer->invers;
10891 
10892     buffer++; /* edge number 57 */
10893     buffer->end=9;
10894     buffer->invers=edges+47;
10895     buffer->min=buffer->invers;
10896 
10897     buffer++; /* edge number 58 */
10898     buffer->end=8;
10899     buffer->invers=edges+42;
10900     buffer->min=buffer->invers;
10901 
10902     buffer++; /* edge number 59  */
10903     buffer->end=7;
10904     buffer->invers=edges+37;
10905     buffer->min=buffer->invers;
10906 
10907     nv=12;
10908     ne=60;
10909 }
10910 
10911 /**************************************************************************/
10912 
10913 static void
initialize_min5(void)10914 initialize_min5(void)
10915 
10916 /* initialize edges for minimum degree 5 generation, and make the
10917    inital icosahedron */
10918 {
10919     EDGE *run,*start;
10920     int n,i;
10921 
10922 /* First initialize the edges for operation a.). They look like
10923 
10924        a
10925     \ / \ /
10926     ?b---c?   Vertex c is the new point. (a,c),(b,c) and (d,c) are the
10927     / \ / \   new edges with a-->c taken as min5_a(n)
10928        d
10929 
10930 a,b and d will be from the old graph -- they cannot be initialised so far.
10931 It is assumed that for 12<=n<MAXN after min5_a(n) there is room for 6 edges.
10932 */
10933 
10934     for (n=12; n<MAXN; n++)
10935       { run=start=min5_a(n);
10936         run->end=n; run->min=run;
10937         run->invers=start+1;
10938 
10939         run=start+1; run->start=n;
10940         run->min=run->invers=start; run->prev=start+3;
10941 
10942         run=start+2; run->end=n; run->min=run; run->invers=start+3;
10943 
10944         run=start+3; run->start=n; run->min=run->invers=start+2;
10945 	run->next=start+1; run->prev=start+5;
10946 
10947         run=start+4; run->end=n; run->min=run; run->invers=start+5;
10948 
10949         run=start+5; run->start=n; run->min=run->invers=start+4;
10950 	run->next=start+3;
10951       }
10952 
10953 
10954 /* The edges for operation b.) look like
10955 
10956 
10957         a
10958      \ / \
10959       b---e-
10960      /|  /|      The new vertices are e,f, the new edges (a,e),(b,e)(c,e),
10961       | / |      (c,f),(d,f)(e,f) with a-->e taken as min5_b0(n)
10962       |/  |/
10963      -c---f
10964        \ / \
10965         d
10966 
10967 It is assumed that after min5_b(n) there is room for 12 edges.
10968 */
10969 
10970     for (n=12; n<MAXN-1; n++)
10971       { run=start=min5_b0(n);
10972         run->end=n; run->min=run;
10973         run->invers=start+1;
10974 
10975         run=start+1; run->start=n;
10976         run->min=run->invers=start; run->prev=start+3;
10977 
10978         run=start+2; run->end=n;
10979         run->min=run; run->invers=start+3 ;
10980 
10981         run=start+3; run->start=n;
10982         run->min=run->invers=start+2; run->prev=start+5; run->next=start+1;
10983 
10984         run=start+4; run->end=n;
10985         run->min=run; run->invers=start+5; run->next=start+8;
10986 
10987         run=start+5; run->start=n;
10988         run->min=run->invers=start+4; run->prev=start+7; run->next=start+3;
10989 
10990         run=start+6; run->start=n+1; run->end=n;
10991         run->min=run; run->invers=start+7; run->prev=start+9;
10992 
10993         run=start+7; run->start=n; run->end=n+1;
10994         run->min=run->invers=start+6; run->next=start+5;
10995 
10996         run=start+8; run->end=n+1;
10997         run->min=run; run->invers=start+9; run->prev=start+4;
10998 
10999         run=start+9; run->start=n+1;
11000         run->min=run->invers=start+8; run->prev=start+11; run->next=start+6;
11001 
11002         run=start+10; run->end=n+1;
11003         run->min=run; run->invers=start+11;
11004 
11005         run=start+11; run->start=n+1;
11006         run->min=run->invers=start+10; run->next=start+9;
11007 
11008       }
11009 
11010     /* The mirror image operation */
11011 
11012     for (n=12; n<MAXN-1; n++)
11013       { run=start=min5_b1(n);
11014         run->end=n; run->min=run;
11015         run->invers=start+1;
11016 
11017         run=start+1; run->start=n;
11018         run->min=run->invers=start; run->next=start+3;
11019 
11020         run=start+2; run->end=n;
11021         run->min=run; run->invers=start+3 ;
11022 
11023         run=start+3; run->start=n;
11024         run->min=run->invers=start+2; run->next=start+5; run->prev=start+1;
11025 
11026         run=start+4; run->end=n;
11027         run->min=run; run->invers=start+5; run->prev=start+8;
11028 
11029         run=start+5; run->start=n;
11030         run->min=run->invers=start+4; run->next=start+7; run->prev=start+3;
11031 
11032         run=start+6; run->start=n+1; run->end=n;
11033         run->min=run; run->invers=start+7; run->next=start+9;
11034 
11035         run=start+7; run->start=n; run->end=n+1;
11036         run->min=run->invers=start+6; run->prev=start+5;
11037 
11038         run=start+8; run->end=n+1;
11039         run->min=run; run->invers=start+9; run->next=start+4;
11040 
11041         run=start+9; run->start=n+1;
11042         run->min=run->invers=start+8; run->next=start+11; run->prev=start+6;
11043 
11044         run=start+10; run->end=n+1;
11045         run->min=run; run->invers=start+11;
11046 
11047         run=start+11; run->start=n+1;
11048         run->min=run->invers=start+10; run->prev=start+9;
11049 
11050       }
11051 
11052 
11053 /* The last operation is c.) It is much too hard too "draw" this way.
11054    The new part that has to be inserted is a vertex of valency 5 surrounded
11055    by 5 vertices of the same valency and the "corona" of them. All this is
11056    inserted into a pentagon. The edge min5_c(n) is one in the corona that
11057    has its start at an old vertex and an edge of the pentagon in next direction. */
11058 
11059     for (n=12; n<MAXN-5; n++)
11060       {
11061 	start=min5_c(n);
11062 
11063 	/* The rotation and starts around the inner vertices is easy: */
11064 
11065 	for (i=0; i<4; i++)
11066 	  { run=start+10+5*i;
11067 	    run->start=n+i; run->prev=run+4; run->next=run+1;
11068 	    run++; run->start=n+i; run->prev=run-1; run->next=run+1;
11069 	    run++; run->start=n+i; run->prev=run-1; run->next=run+1;
11070 	    run++; run->start=n+i; run->prev=run-1; run->next=run+1;
11071 	    run++; run->start=n+i; run->prev=run-1; run->next=run-4;
11072 	  }
11073 	run=start+10+5*i;
11074 	run->prev=run+4; run->next=run+1;
11075 	run++; run->start=n+i; run->prev=run-1; run->next=run+1;
11076 	run++; run->start=n+i; run->prev=run-1; run->next=run+1;
11077 	run++; run->start=n+i; run->prev=run-1; run->next=run+1;
11078 	run++; run->start=n+i; run->prev=run-1; run->next=run-4;
11079 	i++;
11080 	run=start+10+5*i;
11081 	run->start=n+i-1; run->prev=run+4; run->next=run+1;
11082 	run++; run->start=n+i-1; run->prev=run-1; run->next=run+1;
11083 	run++; run->start=n+i-1; run->prev=run-1; run->next=run+1;
11084 	run++; run->start=n+i-1; run->prev=run-1; run->next=run+1;
11085 	run++; run->start=n+i-1; run->prev=run-1; run->next=run-4;
11086 
11087 
11088 
11089 
11090 	/* The edges starting at the boundary 5-gon */
11091 	run=start;
11092 	run->prev=run+1; (run+1)->next=run;
11093 	run+=2; run->prev=run+1; (run+1)->next=run;
11094 	run+=2; run->prev=run+1; (run+1)->next=run;
11095 	run+=2; run->prev=run+1; (run+1)->next=run;
11096 	run+=2; run->prev=run+1; (run+1)->next=run;
11097 
11098 	/* Now all the ends, inverses, and mins */
11099 
11100 	run=start;    run->end=n;   run->min=start; run->invers=start+10;
11101 	run++; /*1*/  run->end=n+1; run->min=run; run->invers=start+15;
11102 	run++; /*2*/  run->end=n+1; run->min=run; run->invers=start+16;
11103 	run++; /*3*/  run->end=n+2; run->min=run; run->invers=start+21;
11104 	run++; /*4*/  run->end=n+2; run->min=run; run->invers=start+22;
11105 	run++; /*5*/  run->end=n+3; run->min=run; run->invers=start+26;
11106 	run++; /*6*/  run->end=n+3; run->min=run; run->invers=start+27;
11107 	run++; /*7*/                run->min=run; run->invers=start+31;
11108 	run++; /*8*/                run->min=run; run->invers=start+32;
11109 	run++; /*9*/  run->end=n;   run->min=run; run->invers=start+14;
11110 	run++; /*10*/               run->min=run->invers=start;
11111 	run++; /*11*/ run->end=n+1; run->min=run; run->invers=start+19;
11112 	run++; /*12*/ run->end=n+4; run->min=run; run->invers=start+35;
11113 	run++; /*13*/               run->min=run; run->invers=start+33;
11114 	run++; /*14*/               run->min=run->invers=start+9;
11115 	run++; /*15*/               run->min=run->invers=start+1;
11116 	run++; /*16*/               run->min=run->invers=start+2;
11117 	run++; /*17*/ run->end=n+2; run->min=run; run->invers=start+20;
11118 	run++; /*18*/ run->end=n+4; run->min=run; run->invers=start+36;
11119 	run++; /*19*/ run->end=n;   run->min=run->invers=start+11;
11120 	run++; /*20*/ run->end=n+1; run->min=run->invers=start+17;
11121 	run++; /*21*/               run->min=run->invers=start+3;
11122 	run++; /*22*/               run->min=run->invers=start+4;
11123 	run++; /*23*/ run->end=n+3; run->min=run; run->invers=start+25;
11124 	run++; /*24*/ run->end=n+4; run->min=run; run->invers=start+37;
11125 	run++; /*25*/ run->end=n+2; run->min=run->invers=start+23;
11126 	run++; /*26*/               run->min=run->invers=start+5;
11127 	run++; /*27*/               run->min=run->invers=start+6;
11128 	run++; /*28*/               run->min=run; run->invers=start+30;
11129 	run++; /*29*/ run->end=n+4; run->min=run; run->invers=start+38;
11130 	run++; /*30*/ run->end=n+3; run->min=run->invers=start+28;
11131 	run++; /*31*/               run->min=run->invers=start+7;
11132 	run++; /*32*/               run->min=run->invers=start+8;
11133 	run++; /*33*/ run->end=n;   run->min=run->invers=start+13;
11134 	run++; /*34*/ run->end=n+4; run->min=run; run->invers=start+39;
11135 	run++; /*35*/ run->end=n;   run->min=run->invers=start+12;
11136 	run++; /*36*/ run->end=n+1; run->min=run->invers=start+18;
11137 	run++; /*37*/ run->end=n+2; run->min=run->invers=start+24;
11138 	run++; /*38*/ run->end=n+3; run->min=run->invers=start+29;
11139 	run++; /*39*/               run->min=run->invers=start+34;
11140 
11141       }
11142 
11143    make_icosahedron();
11144 }
11145 
11146 /**************************************************************************/
11147 
11148 static EDGE*
extend_min5_c(EDGE * e,EDGE ** anchor)11149 extend_min5_c(EDGE *e, EDGE **anchor)
11150 
11151 {
11152 /* extends a graph in the way given by the type c extension for
11153    5-connected triangulations. The edge e must start at
11154    a vertex of degree 5.
11155 
11156    It returns the edge characterizing this operation. This edge as
11157    well as the edge pointed to by *anchor must be given to the reduction
11158    routine.
11159 
11160 */
11161 
11162   EDGE *e1, *e2, *e3, *e4, *e5, *e1i, *e2i, *e3i, *e4i, *e5i, *start, *run;
11163   int v1, v2, v3, v4, v5, origin;
11164 
11165   *anchor=e;
11166 
11167   e1=e->invers->next;
11168   e1i=e1->invers;
11169   e2=e1i->next->next;
11170   e2i=e2->invers;
11171   e3=e2i->next->next;
11172   e3i=e3->invers;
11173   e4=e3i->next->next;
11174   e4i=e4->invers;
11175   e5=e4i->next->next;
11176   e5i=e5->invers;
11177 
11178   origin=e->start;
11179   v1=e1->start;
11180   v2=e1->end;
11181   v3=e3->start;
11182   v4=e3->end;
11183   v5=e5->start;
11184 
11185   start=min5_c(nv);
11186 
11187   firstedge[v1]=e1;
11188   degree[v1]++;
11189   firstedge[v2]=e2;
11190   degree[v2]++;
11191   firstedge[v3]=e3;
11192   degree[v3]++;
11193   firstedge[v4]=e4;
11194   degree[v4]++;
11195   firstedge[v5]=e5;
11196   degree[v5]++;
11197 
11198   firstedge[nv]=start+10; degree[nv]=5; nv++;
11199   firstedge[nv]=start+16; degree[nv]=5; nv++;
11200   firstedge[nv]=start+23; degree[nv]=5; nv++;
11201   firstedge[nv]=start+28; degree[nv]=5; nv++;
11202   firstedge[nv]=start+35; degree[nv]=5; nv++;
11203   firstedge[origin]=start+32;
11204   /* degree[nv]=5; is already the case */
11205 
11206   ne+=30;
11207 
11208   e1->prev=start; start->next=e1;
11209   run=start+1;
11210   e5i->next=run; run->prev=e5i;
11211   run++;
11212   e5->prev=run; run->next=e5;
11213   run++;
11214   e4i->next=run; run->prev=e4i;
11215   run++;
11216   e4->prev=run; run->next=e4;
11217   run++;
11218   e3i->next=run; run->prev=e3i;
11219   run++;
11220   e3->prev=run; run->next=e3;
11221   run++;
11222   e2i->next=run; run->prev=e2i;
11223   run++;
11224   e2->prev=run; run->next=e2;
11225   run++;
11226   e1i->next=run; run->prev=e1i;
11227 
11228   start->start=(start+1)->start=(start+10)->end=(start+15)->end=v1;
11229   (start+8)->start=(start+9)->start=(start+14)->end=(start+32)->end=v2;
11230   (start+7)->start=(start+6)->start=(start+27)->end=(start+31)->end=v3;
11231   (start+4)->start=(start+5)->start=(start+22)->end=(start+26)->end=v4;
11232   (start+2)->start=(start+3)->start=(start+16)->end=(start+21)->end=v5;
11233   (start+8)->end=(start+13)->end=(start+39)->end=(start+28)->end=(start+7)->end=origin;
11234   (start+30)->start=(start+31)->start=(start+32)->start=(start+33)->start=
11235      (start+34)->start=origin;
11236 
11237   return (start+35);
11238 
11239 }
11240 
11241 /**************************************************************************/
11242 
11243 static void
reduce_min5_c(EDGE * e,EDGE * anchor)11244 reduce_min5_c(EDGE *e, EDGE *anchor)
11245 {
11246 
11247   /* Like other reduction operations, this is not the reverse operation,
11248      but it relies on the map being EXACTLY the same as after the application
11249      of the corresponding extend operation */
11250 
11251   EDGE *e1, *e2, *e3, *e4, *e5, *e1i, *e2i, *e3i, *e4i, *e5i;
11252   int v1, v2, v3, v4, v5, origin;
11253 
11254   e1=e->invers->prev->prev->invers->next;
11255   e1i=e1->invers;
11256   e2=e1i->next->next->next;
11257   e2i=e2->invers;
11258   e3=e2i->next->next->next;
11259   e3i=e3->invers;
11260   e4=e3i->next->next->next;
11261   e4i=e4->invers;
11262   e5=e4i->next->next->next;
11263   e5i=e5->invers;
11264 
11265   v1=e1->start;
11266   v2=e1->end;
11267   v3=e3->start;
11268   v4=e3->end;
11269   v5=e5->start;
11270   origin=anchor->start;
11271 
11272   firstedge[v1]=e1;
11273   degree[v1]--;
11274   firstedge[v2]=e2;
11275   degree[v2]--;
11276   firstedge[v3]=e3;
11277   degree[v3]--;
11278   firstedge[v4]=e4;
11279   degree[v4]--;
11280   firstedge[v5]=e5;
11281   degree[v5]--;
11282   firstedge[origin]=anchor;
11283 
11284   nv-=5; ne-=30;
11285 
11286   e1->prev=e5i->next=anchor->invers;
11287   anchor=anchor->prev;
11288   e2->prev=e1i->next=anchor->invers;
11289   anchor=anchor->prev;
11290   e3->prev=e2i->next=anchor->invers;
11291   anchor=anchor->prev;
11292   e4->prev=e3i->next=anchor->invers;
11293   anchor=anchor->prev;
11294   e5->prev=e4i->next=anchor->invers;
11295 }
11296 
11297 /**************************************************************************/
11298 
11299 static int
on_nf_5_cycle(EDGE * e)11300 on_nf_5_cycle(EDGE *e)
11301 /* nf means that there are vertices inside both parts of the
11302    triangulation separated by the cycle.
11303 
11304    Assumes that there are no nf-4-cycles in the graph. This means that
11305    at ANY vertex of the cycle there is an edge pointing into EACH of the
11306    two components.
11307 
11308    Assumes further that the valency of all vertices involved is at least 5.
11309 
11310    Returns TRUE, if edge e is on an nf-5cycle, FALSE otherwise
11311 */
11312 
11313 {
11314   EDGE *run, *run1, *last, *last1, *dummy;
11315 
11316   if ((degree[e->next->end]==5) || (degree[e->prev->end]==5)) return TRUE;
11317 
11318   RESETMARKS_V;
11319   last=e->prev->prev;
11320   run=e->next->next;
11321     dummy=run->invers;
11322     last1=dummy->prev->prev;
11323     run1=dummy->next->next;
11324     MARK_V(run1->end);
11325     run1=run1->next;
11326     MARK_V(run1->end);
11327     while (run1!=last1) { run1=run1->next; MARK_V(run1->end); }
11328   run=run->next;
11329     dummy=run->invers;
11330     last1=dummy->prev->prev;
11331     run1=dummy->next->next;
11332     MARK_V(run1->end);
11333     run1=run1->next;
11334     MARK_V(run1->end);
11335     while (run1!=last1) { run1=run1->next; MARK_V(run1->end); }
11336   while (run!=last)
11337     { run=run->next;
11338       dummy=run->invers;
11339       last1=dummy->prev->prev;
11340       run1=dummy->next->next;
11341       MARK_V(run1->end);
11342       run1=run1->next;
11343       MARK_V(run1->end);
11344       while (run1!=last1) { run1=run1->next; MARK_V(run1->end); }
11345     }
11346 
11347   e=e->invers;
11348 
11349   last=e->prev->prev;
11350   run=e->next->next;
11351     dummy=run->invers;
11352     last1=dummy->prev->prev;
11353     run1=dummy->next->next;
11354     if (ISMARKED_V(run1->end)) return TRUE;
11355     run1=run1->next;
11356     if (ISMARKED_V(run1->end)) return TRUE;
11357     while (run1!=last1) { run1=run1->next; if (ISMARKED_V(run1->end)) return TRUE; }
11358   run=run->next;
11359     dummy=run->invers;
11360     last1=dummy->prev->prev;
11361     run1=dummy->next->next;
11362     if (ISMARKED_V(run1->end)) return TRUE;
11363     run1=run1->next;
11364     if (ISMARKED_V(run1->end)) return TRUE;
11365     while (run1!=last1) { run1=run1->next; if (ISMARKED_V(run1->end)) return TRUE; }
11366   while (run!=last)
11367     { run=run->next;
11368       dummy=run->invers;
11369       last1=dummy->prev->prev;
11370       run1=dummy->next->next;
11371       if (ISMARKED_V(run1->end)) return TRUE;
11372       run1=run1->next;
11373       if (ISMARKED_V(run1->end)) return TRUE;
11374       while (run1!=last1) { run1=run1->next; if (ISMARKED_V(run1->end)) return TRUE; }
11375     }
11376 
11377   return FALSE;
11378 }
11379 
11380 /**************************************************************************/
11381 
11382 static void
find_extensions_min5(int nbtot,int nbop,EDGE * extA1[],EDGE * extA2[],int * nextA,EDGE * extB[],int extBmirror[],int * nextB,EDGE * extC[],int * nextC,EDGE * lastA)11383 find_extensions_min5(int nbtot, int nbop, EDGE *extA1[], EDGE *extA2[],
11384    int *nextA, EDGE *extB[], int extBmirror[], int *nextB,
11385    EDGE *extC[], int *nextC, EDGE *lastA)
11386 
11387 /* Determine the inequivalent places to make extensions, for the
11388    ordinary triangulations of minimum degree 5.  The results are
11389    put in the arrays extD1[0..*nextD-1], etc..
11390    nbtot and nbop are the usual group parameters.
11391    If lastA != NULL, this graph was made with an A-operation and lastA
11392    is its central edge.  If lastA == NULL, it wasn't made with A.
11393 */
11394 {
11395     register int i,k;
11396     register EDGE *e,*e1,*e2,*elast,*elast1,*elast2;
11397     EDGE **nb,**nb0,**nblim,**nboplim,**nb1,**nb2;
11398     int v1,v2,d1,d2,xd1,xd2,oldcola,oldcolb,alpha,cola,colb;
11399 
11400 
11401     RESETMARKS_V;
11402     if (lastA)
11403     {
11404         v1 = lastA->start;
11405 	v2 = lastA->end;
11406 	d1 = degree[v1];
11407 	d2 = degree[v2];
11408         MARK_V(v1);
11409         MARK_V(v2);
11410         MARK_V(lastA->prev->end);
11411         MARK_V(lastA->next->end);
11412     }
11413 
11414     if (nbtot == 1)
11415     {
11416       /* A-extensions, trivial group */
11417 
11418 	k = 0;
11419 	for (i = 0; i < nv; ++i)
11420 	if (degree[i] >= 6)
11421 	{
11422 	    cola = degree[i] + 4;
11423 
11424 	    if (ISMARKED_V(i) || !lastA || cola >= d1+d2+2)
11425 	    {
11426 	        e1 = elast1 = firstedge[i];
11427                 do
11428                 {
11429 		    e2 = e1->next->next->next;
11430 		    elast2 = e1->prev->prev;
11431 		    do
11432 		    {
11433 		        if (e2 > e1)
11434 		        {
11435 			    extA1[k] = e1;
11436 			    extA2[k] = e2;
11437 			    ++k;
11438 		        }
11439 		        e2 = e2->next;
11440 		    } while (e2 != elast2);
11441 		    e1 = e1->next;
11442 	        } while (e1 != elast1);
11443 	    }
11444 	    else if (cola < d1+d2)
11445 		continue;
11446 	    else
11447             {
11448                 e1 = elast1 = firstedge[i];
11449                 do
11450                 {
11451                     e2 = e1->next->next->next;
11452                     elast2 = e1->prev->prev;
11453                     alpha = 2;
11454                     do
11455                     {
11456                         if (e2 > e1)
11457                         {
11458 			    if (e1->end == v1 || e2->end == v1) xd1 = d1+1;
11459 			    else                                xd1 = d1;
11460 			    if (e1->end == v2 || e2->end == v2) xd2 = d2+1;
11461 			    else                                xd2 = d2;
11462 
11463 			    oldcola = xd1 + xd2;
11464 			    if (cola > oldcola)
11465 			    {
11466                                 extA1[k] = e1;
11467                                 extA2[k] = e2;
11468                                 ++k;
11469 			    }
11470 			    else if (cola == oldcola)
11471 			    {
11472 			        oldcolb = MIN(xd1,xd2);
11473 				colb = 3 + MIN(alpha,degree[i]-alpha-2);
11474 			   	if (colb >= oldcolb)
11475 			        {
11476                                     extA1[k] = e1;
11477                                     extA2[k] = e2;
11478                                     ++k;
11479 			        }
11480 			    }
11481                         }
11482                         ++alpha;
11483                         e2 = e2->next;
11484                     } while (e2 != elast2);
11485                     e1 = e1->next;
11486                 } while (e1 != elast1);
11487             }
11488 	}
11489 
11490 	*nextA = k;
11491 
11492       /* B-extensions, trivial group */
11493 
11494 	if (lastA || nv >= maxnv-1)
11495 	    *nextB = 0;
11496 	else
11497 	{
11498             k = 0;
11499 
11500 	    for (i = 0; i < nv; ++i)
11501 	    if (degree[i] == 5)
11502 	    {
11503 		e = elast = firstedge[i];
11504 		do
11505 		{
11506 		    if (degree[e->end] == 5 && e == e->min)
11507 		    {
11508 			extB[k] = extB[k+1] = e;
11509 			extBmirror[k] = FALSE;
11510 			extBmirror[k+1] = TRUE;
11511 			k += 2;
11512 		    }
11513 		    e = e->next;
11514 		} while (e != elast);
11515 	    }
11516 	    *nextB = k;
11517 	}
11518 
11519       /* C-extensions, trivial group */
11520 
11521 	if (nv >= maxnv-4)
11522 	    *nextC = 0;
11523 	else
11524 	{
11525 	    k = 0;
11526 	    for (i = 0; i < nv; ++i)
11527 		if (degree[i] == 5) extC[k++] = firstedge[i];
11528 	    *nextC = k;
11529 	}
11530     }
11531     else
11532     {
11533         nb0 = (EDGE**)numbering[0];
11534         nboplim = (EDGE**)numbering[nbop==0?nbtot:nbop];
11535         nblim = (EDGE**)numbering[nbtot];
11536 
11537 	for (i = 0; i < ne; ++i) nb0[i]->index = i;
11538 
11539       /* A-extensions, non-trivial group */
11540 
11541 	k = 0;
11542 
11543 	for (i = 0; i < nv; ++i)
11544 	if (degree[i] >= 6)
11545 	{
11546             if (!ISMARKED_V(i) && lastA && degree[i]+4 < d1+d2) continue;
11547 
11548 	    e1 = elast1 = firstedge[i];
11549             do
11550             {
11551 		e2 = e1->next->next->next;
11552 		elast2 = e1->prev->prev;
11553 		do
11554 		{
11555 		    if (e1 < e2)
11556 		    {
11557 			nb1 = &nb0[e1->index + MAXE];
11558 			nb2 = &nb0[e2->index + MAXE];
11559 			for ( ; nb1 < nblim; nb1 += MAXE, nb2 += MAXE)
11560 			    if (*nb1 < *nb2)
11561 			    {
11562 				if (*nb1 < e1 || (*nb1 == e1 && *nb2 < e2))
11563 				    break;
11564 			    }
11565 			    else
11566 			    {
11567 				if (*nb2 < e1 || (*nb2 == e1 && *nb1 < e2))
11568 				    break;
11569 			    }
11570 
11571 			if (nb1 >= nblim)
11572 			{
11573 			    extA1[k] = e1;
11574 			    extA2[k] = e2;
11575 			    ++k;
11576 			}
11577 		    }
11578 		    e2 = e2->next;
11579 		} while (e2 != elast2);
11580 		e1 = e1->next;
11581 	    } while (e1 != elast1);
11582 	}
11583 
11584 	*nextA = k;
11585 
11586       /* B-extensions, non-trivial group */
11587 
11588         if (lastA || nv >= maxnv-1)
11589             *nextB = 0;
11590         else
11591         {
11592             k = 0;
11593             RESETMARKS;
11594 
11595 	    for (i = 0; i < ne; ++i)
11596 		if (!ISMARKEDLO(nb0[i]) && degree[nb0[i]->start] == 5
11597 					 && degree[nb0[i]->end] == 5)
11598 		{
11599 		    extB[k] = nb0[i]->min;
11600 		    if (nb0[i] == nb0[i]->min)
11601 		    {
11602 			extBmirror[k] = TRUE;
11603 
11604 		        for (nb = &nb0[i]; nb < nboplim; nb += MAXE)
11605 			    MARKLO((*nb)->min);
11606 		        for ( ; nb < nblim; nb += MAXE)
11607 			    MARKLO((*nb)->min->invers);
11608 		    }
11609 		    else
11610                     {
11611                         extBmirror[k] = FALSE;
11612 
11613                         for (nb = &nb0[i]; nb < nboplim; nb += MAXE)
11614                             MARKLO((*nb)->min->invers);
11615                         for ( ; nb < nblim; nb += MAXE)
11616                             MARKLO((*nb)->min);
11617                     }
11618 		    ++k;
11619 		}
11620 
11621 	    *nextB = k;
11622 	}
11623 
11624       /* C-extensions, non-trivial group */
11625 
11626         if (nv >= maxnv-4)
11627             *nextC = 0;
11628         else
11629         {
11630             k = 0;
11631 
11632 	    RESETMARKS_V;
11633 	    for (i = 0; i < nv; ++i)
11634 	        if (!ISMARKED_V(i) && degree[i] == 5)
11635 		{
11636 		    extC[k++] = firstedge[i];
11637 		    for (nb = nb0+firstedge[i]->index; nb < nblim; nb += MAXE)
11638 			MARK_V((*nb)->start);
11639 		}
11640 	    *nextC = k;
11641 	}
11642     }
11643 }
11644 
11645 /**************************************************************************/
11646 
11647 static void
min5_a_legal(EDGE * ref,EDGE * good_or[],int * ngood_or,int * ngood_ref,EDGE * good_mir[],int * ngood_mir,int * ngood_mir_ref,EDGE ** prevA,int nprevA)11648 min5_a_legal(EDGE *ref, EDGE *good_or[], int *ngood_or, int *ngood_ref,
11649              EDGE *good_mir[], int *ngood_mir, int *ngood_mir_ref,
11650              EDGE **prevA, int nprevA)
11651 
11652 /* The A-operation with reference edge *ref has just been performed.
11653    prevA[0..nprevA-1] are all earlier As since the last B or C.
11654    Make a list in good_or[0..*ngood_or-1] of the reference edges of
11655    legal A-reductions (oriented editions) that might be canonical,
11656    with the first *ngood_ref of those being ref.
11657    Make a list in good_mir[0..*ngood_mir-1] of the
11658    reference edges of legal four-reductions (mirror-image editions)
11659    that might be canonical, with the first *ngood_mir_ref of those being
11660    ref->next.
11661    *ngood_ref and *ngood_mir_ref might each be 0-2.  If they are
11662    both 0, nothing else need be correct.
11663    All the edges in good_or[] and good_mir[] must start with the same
11664    vertex degree and end with the same vertex degree (actually, colour
11665    as passed to canon_edge_oriented).
11666    A-reductions have a priority (colour) based on the degrees of the
11667    four central vertices.  It cannot be changed without changing
11668    extensions_min5 too.
11669 */
11670 {
11671     EDGE *e;
11672     int deg1,deg2,deg3,deg4,d1,d2,d3,d4;
11673     long bestcol1,bestcol2,col1,col2;
11674     int nor,nmir,i;
11675     int mind1,mind2,maxdeg12,sumdeg12;
11676     EDGE *ei,*eilast,*hint;
11677 #define PAIR(x,y) (((long)((x)+(y))<<10)+(long)(x))
11678 #define UPAIR(x,y) ((x)<(y) ? PAIR(x,y) : PAIR(y,x))
11679 
11680     e = ref;
11681     deg1 = degree[e->start];
11682     deg2 = degree[e->end];
11683     deg3 = degree[e->prev->end];
11684     deg4 = degree[e->next->end];
11685 
11686     bestcol1 = UPAIR(deg1,deg2);
11687     bestcol2 = UPAIR(deg3,deg4);
11688 
11689     RESETMARKS;
11690     MARKLO(e);
11691     MARKLO(e->invers);
11692 
11693     nor = nmir = 0;
11694 
11695     for (i = nprevA; --i >= 0;)
11696     {
11697 	hint = prevA[i];
11698  	MARKLO(hint);
11699  	MARKLO(hint->invers);
11700         if ((d3 = degree[hint->prev->end]) >= 6
11701                       && (d4 = degree[hint->next->end]) >= 6)
11702         {
11703            /* Theorem: The reference edges of the A-expansions since the
11704               most recent B- or C-expansion are not on essential 5-cycles. */
11705             d1 = degree[hint->start];
11706             d2 = degree[hint->end];
11707             col1 = UPAIR(d1,d2);
11708 	    if (col1 == bestcol1)
11709 	    {
11710                 col2 = UPAIR(d3,d4);
11711                 if (col2 > bestcol2)
11712                 {
11713                     *ngood_ref = *ngood_mir_ref = 0;
11714                     return;
11715                 }
11716 	        else if (col2 == bestcol2)
11717     	        {
11718 		    if (nor + nmir == 0)
11719 		    {
11720     		        if (deg1 >= deg2)
11721     		        {
11722         		    if (deg3 >= deg4) good_or[nor++] = e;
11723         		    if (deg3 <= deg4) good_mir[nmir++] = e;
11724     		        }
11725     		        if (deg1 <= deg2)
11726     		        {
11727         		    if (deg3 <= deg4) good_or[nor++] = e->invers;
11728         		    if (deg3 >= deg4) good_mir[nmir++] = e->invers;
11729     		        }
11730 		        *ngood_ref = nor;
11731     		        *ngood_mir_ref = nmir;
11732 		    }
11733 
11734         	    if (d1 >= d2)
11735         	    {
11736             	        if (d3 >= d4) good_or[nor++] = hint;
11737             	        if (d3 <= d4) good_mir[nmir++] = hint;
11738         	    }
11739         	    if (d1 <= d2)
11740         	    {
11741             	        if (d3 <= d4) good_or[nor++] = hint->invers;
11742             	        if (d3 >= d4) good_mir[nmir++] = hint->invers;
11743         	    }
11744     	        }
11745 	    }
11746 	    else if (col1 > bestcol1)
11747             {
11748                 *ngood_ref = *ngood_mir_ref = 0;
11749                 return;
11750             }
11751 	}
11752     }
11753 
11754     if (nor + nmir == 0)
11755     {
11756         if (deg1 >= deg2)
11757         {
11758             if (deg3 >= deg4) good_or[nor++] = e;
11759             if (deg3 <= deg4) good_mir[nmir++] = e;
11760         }
11761         if (deg1 <= deg2)
11762         {
11763             if (deg3 <= deg4) good_or[nor++] = e->invers;
11764             if (deg3 >= deg4) good_mir[nmir++] = e->invers;
11765         }
11766 
11767         *ngood_ref = nor;
11768         *ngood_mir_ref = nmir;
11769     }
11770 
11771     if (nor > *ngood_ref || nmir > *ngood_mir_ref)
11772         prune_oriented_lists(good_or,&nor,ngood_ref,
11773                              good_mir,&nmir,ngood_mir_ref);
11774 
11775     if (*ngood_ref+*ngood_mir_ref == 0) return;
11776 
11777     sumdeg12 = deg1 + deg2;
11778     mind1 = (sumdeg12 + 1) / 2;
11779     maxdeg12 = MAX(deg1,deg2);
11780 
11781     for (i = nv; --i >= 0;)
11782     if ((d1 = degree[i]) >= mind1)
11783     {
11784 	if (d1 <= maxdeg12) mind2 = sumdeg12 - d1;
11785 	else                mind2 = sumdeg12 - d1 + 1;
11786 
11787 	ei = eilast = firstedge[i];
11788 	do
11789 	{
11790             if (!ISMARKEDLO(ei) && (d2 = degree[ei->end]) >= mind2
11791                                 && (d3 = degree[ei->prev->end]) >= 6
11792                                 && (d4 = degree[ei->next->end]) >= 6)
11793 	    {
11794 		col1 = UPAIR(d1,d2);
11795 
11796 		if (col1 > bestcol1)
11797 		{
11798 		    if (!on_nf_5_cycle(ei))
11799 		    {
11800 			*ngood_ref = *ngood_mir_ref = 0;
11801 			return;
11802 		    }
11803 		}
11804 		else
11805 		{
11806 		    col2 = UPAIR(d3,d4);
11807 		    if (col2 > bestcol2)
11808                     {
11809                         if (!on_nf_5_cycle(ei))
11810                         {
11811                             *ngood_ref = *ngood_mir_ref = 0;
11812                             return;
11813                         }
11814                     }
11815 		    else if (col2 == bestcol2 && !on_nf_5_cycle(ei))
11816 		    {
11817 	                if (d1 >= d2)
11818     		        {
11819         		    if (d3 >= d4) good_or[nor++] = ei;
11820         		    if (d3 <= d4) good_mir[nmir++] = ei;
11821     		        }
11822     		        if (d1 <= d2)
11823     		        {
11824         		    if (d3 <= d4) good_or[nor++] = ei->invers;
11825         		    if (d3 >= d4) good_mir[nmir++] = ei->invers;
11826     		        }
11827 		    }
11828 	        }
11829 	    }
11830 	    MARKLO(ei->invers);
11831 	    ei = ei->next;
11832 	} while (ei != eilast);
11833     }
11834 
11835     if (nor > *ngood_ref || nmir > *ngood_mir_ref)
11836         prune_oriented_lists(good_or,&nor,ngood_ref,
11837                              good_mir,&nmir,ngood_mir_ref);
11838 
11839     *ngood_or = nor;
11840     *ngood_mir = nmir;
11841 }
11842 
11843 /**************************************************************************/
11844 
11845 static int
is_valid_min5_b(EDGE * ref,int mirror)11846 is_valid_min5_b(EDGE *ref, int mirror)
11847 
11848 /* Check if the B-reduction (ref,mirror) is valid.  The important
11849    things are that two vertices have degree >= 6 and there are no
11850    non-facial 5-cycles that will become non-facial 4-cycles.
11851    It is assumed that the ends and sides of ref have degree 5.
11852 */
11853 
11854 {
11855     EDGE *e1,*e2,*e,*refi;
11856 
11857     refi = ref->invers;
11858 
11859     if (!mirror)
11860     {
11861 	if (degree[ref->next->next->end] < 6
11862 				         || degree[refi->next->next->end] < 6)
11863 	    return FALSE;
11864 	e1 = ref->prev->prev->invers->prev->prev;
11865 	e2 = refi->prev->prev->invers->prev->prev;
11866 
11867 	RESETMARKS_V;
11868 
11869 	for (e = e1->next->next->next->next; e != e1; e = e->next)
11870 	    MARK_V(e->end);
11871 	e1 = e1->invers;
11872 	for (e = e1->prev->prev->prev; e != e1; e = e->prev)
11873 	    MARK_V(e->end);
11874 
11875 	for (e = e2->next->next->next->next; e != e2; e = e->next)
11876 	    if (ISMARKED_V(e->end)) return FALSE;
11877 	e2 = e2->invers;
11878         for (e = e2->prev->prev->prev; e != e2; e = e->prev)
11879             if (ISMARKED_V(e->end)) return FALSE;
11880     }
11881     else
11882     {
11883         if (degree[ref->prev->prev->end] < 6
11884                                          || degree[refi->prev->prev->end] < 6)
11885             return FALSE;
11886         e1 = ref->next->next->invers->next->next;
11887         e2 = refi->next->next->invers->next->next;
11888 
11889         RESETMARKS_V;
11890 
11891 	for (e = e1->prev->prev->prev->prev; e != e1; e = e->prev)
11892             MARK_V(e->end);
11893         e1 = e1->invers;
11894         for (e = e1->next->next->next; e != e1; e = e->next)
11895             MARK_V(e->end);
11896 
11897         for (e = e2->prev->prev->prev->prev; e != e2; e = e->prev)
11898             if (ISMARKED_V(e->end)) return FALSE;
11899         e2 = e2->invers;
11900         for (e = e2->next->next->next; e != e2; e = e->next)
11901             if (ISMARKED_V(e->end)) return FALSE;
11902     }
11903 
11904     return TRUE;
11905 }
11906 
11907 /**************************************************************************/
11908 
11909 static int
has_min5_a(void)11910 has_min5_a(void)
11911 
11912 /* Test if the graph has an A-reduction */
11913 
11914 {
11915     EDGE *e,*elast;
11916     int i;
11917 
11918     for (i = 0; i < nv; ++i)
11919     {
11920         e = elast = firstedge[i];
11921         do
11922         {
11923             if (e == e->min && degree[e->next->end] >= 6
11924                     && degree[e->prev->end] >= 6 && !on_nf_5_cycle(e))
11925                 return TRUE;
11926             e = e->next;
11927         } while (e != elast);
11928     }
11929 
11930     return FALSE;
11931 }
11932 
11933 /**************************************************************************/
11934 
11935 static int
has_min5_b(void)11936 has_min5_b(void)
11937 
11938 /* Test if the graph has a B-reduction */
11939 
11940 {
11941     EDGE *e,*elast;
11942     int i;
11943 
11944     for (i = 0; i < nv; ++i)
11945     if (degree[i] == 5)
11946     {
11947         e = elast = firstedge[i];
11948         do
11949         {
11950             if (e == e->min && degree[e->end] == 5
11951                     && degree[e->prev->end] == 5
11952                     && degree[e->next->end] == 5
11953 		    && (is_valid_min5_b(e,FALSE) || is_valid_min5_b(e,TRUE)))
11954                 return TRUE;
11955             e = e->next;
11956         } while (e != elast);
11957     }
11958 
11959     return FALSE;
11960 }
11961 
11962 /**************************************************************************/
11963 
11964 static void
min5_b_legal(EDGE * ref,int mirror,EDGE * good_or[],int * ngood_or,int * ngood_ref,EDGE * good_mir[],int * ngood_mir,int * ngood_mir_ref)11965 min5_b_legal(EDGE *ref, int mirror, EDGE *good_or[], int *ngood_or,
11966    int *ngood_ref, EDGE *good_mir[], int *ngood_mir, int *ngood_mir_ref)
11967 
11968 /* The B-operation with reference edge *ref and side mirror has just been
11969    performed.
11970    Make a list in good_or[0..*ngood_or-1] of the reference edges of
11971    legal B-reductions (oriented editions) that might be canonical,
11972    with the first *ngood_ref of those being ref.
11973    Make a list in good_mir[0..*ngood_mir-1] of the
11974    reference edges of legal four-reductions (mirror-image editions)
11975    that might be canonical, with the first *ngood_mir_ref of those being
11976    ref->next.
11977    *ngood_ref and *ngood_mir_ref might each be 0-2.  If they are
11978    both 0, nothing else need be correct.
11979    All the edges in good_or[] and good_mir[] must start with the same
11980    vertex degree and end with the same vertex degree (actually, colour
11981    as passed to canon_edge_oriented).
11982    This procedure does NOT determine that there are no A-reductions.
11983 */
11984 {
11985     EDGE *e,*elast;
11986     int nor,nmir,i;
11987 
11988     ref = ref->min;
11989     nor = nmir = 0;
11990 
11991     if (!mirror)
11992     {
11993 	good_or[nor++] = ref;
11994 	good_or[nor++] = ref->invers;
11995     }
11996     else
11997     {
11998 	good_mir[nmir++] = ref;
11999 	good_mir[nmir++] = ref->invers;
12000     }
12001 
12002     *ngood_ref = nor;
12003     *ngood_mir_ref = nmir;
12004 
12005     RESETMARKS;
12006     MARKLO(ref);
12007 
12008     for (i = 0; i < nv; ++i)
12009     if (degree[i] == 5)
12010     {
12011 	e = elast = firstedge[i];
12012 	do
12013 	{
12014 	    if (e == e->min && !ISMARKEDLO(e) && degree[e->prev->end] == 5
12015 			&& degree[e->end] == 5 && degree[e->next->end] == 5)
12016 	    {
12017 		if (is_valid_min5_b(e,FALSE))
12018 		{
12019         	    good_or[nor++] = e;
12020         	    good_or[nor++] = e->invers;
12021     		}
12022 		if (is_valid_min5_b(e,TRUE))
12023 		{
12024         	    good_mir[nmir++] = e;
12025         	    good_mir[nmir++] = e->invers;
12026 		}
12027 	    }
12028 	    e = e->next;
12029 	} while (e != elast);
12030     }
12031 
12032     if (nor > *ngood_ref || nmir > *ngood_mir_ref)
12033         prune_oriented_lists(good_or,&nor,ngood_ref,
12034                              good_mir,&nmir,ngood_mir_ref);
12035 
12036     *ngood_or = nor;
12037     *ngood_mir = nmir;
12038 }
12039 
12040 /**************************************************************************/
12041 
12042 static int
is_min5_c_centre(int v)12043 is_min5_c_centre(int v)
12044 
12045 /* checks whether the configuration centered at vertex v is reducible by
12046    the c-reduction of the min5 generation.
12047 
12048    It assumes that there is no nf-4-cycle in the graph. It can be
12049    shown that it is enough to check the valencies of the center and its
12050    neighbours to be 5 and the second neighbours to be at least 6. In this
12051    case a 4-cut introduced by the reduction would imply that there was one
12052    before.
12053 
12054 */
12055 
12056 {
12057 
12058   EDGE *run;
12059 
12060   if (degree[v]!=5) return FALSE;
12061 
12062   run=firstedge[v]; if(degree[run->end]!=5) return FALSE;
12063   run=run->next; if(degree[run->end]!=5) return FALSE;
12064   run=run->next; if(degree[run->end]!=5) return FALSE;
12065   run=run->next; if(degree[run->end]!=5) return FALSE;
12066   run=run->next; if(degree[run->end]!=5) return FALSE;
12067 
12068   run=run->invers->prev->prev->invers->next; /* edge 1*/
12069   if ((degree[run->start]<6) || (degree[run->end]<6)) return FALSE;
12070   run=run->invers->next->next->next; /* edge 2*/
12071   if (degree[run->end]<6) return FALSE;
12072   run=run->invers->next->next->next; /* edge 3*/
12073   if (degree[run->end]<6) return FALSE;
12074   run=run->invers->next->next->next; /* edge 4*/
12075   if (degree[run->end]<6) return FALSE;
12076 
12077   return TRUE;
12078 }
12079 
12080 /**************************************************************************/
12081 
12082 static void
scanmin5c(int nbtot,int nbop,int dosplit,EDGE ** prevA,int nprevA)12083 scanmin5c(int nbtot, int nbop, int dosplit, EDGE **prevA, int nprevA)
12084 
12085 /* The main node of the recursion for 5-connected triangulations.
12086    As this procedure is entered, nv,ne,degree etc are set for some graph,
12087    and nbtot/nbop are the values returned by canon() for that graph.
12088    If dosplit==TRUE, this is the place to do splitting (if any).
12089    prev[0..nprevA-1] is the list of consecutive A operations leading
12090    to this graph, given by their central edges.
12091    If nprevA == 0, this graph wasn't made with A.
12092 */
12093 {
12094     EDGE *firstedge_save[MAXN];
12095     EDGE *extA1[MAXN*MAXN/4+10],*extA2[MAXN*MAXN/4+10],
12096          *extB[MAXE],*extC[MAXN];
12097     EDGE *extAred,*extBred,*extCred,*extCanchor;
12098     int extBmirror[MAXE];
12099     EDGE *good_or[MAXE],*good_mir[MAXE];
12100     EDGE *newprevA[MAXN];
12101     int ngood_or,ngood_mir,ngood_ref,ngood_mir_ref;
12102     int nextA,nextB,nextC,i,j;
12103     int xnbtot,xnbop;
12104     int colour[MAXN];
12105 
12106     if (nv == maxnv)
12107     {
12108         got_one(nbtot,nbop,5);
12109 	return;
12110     }
12111 
12112     if (dosplit)
12113     {
12114 #ifdef SPLITTEST
12115         ++splitcases;
12116         return;
12117 #endif
12118         if (splitcount-- != 0) return;
12119         splitcount = mod - 1;
12120 
12121         for (i = 0; i < nv; ++i) firstedge_save[i] = firstedge[i];
12122     }
12123 
12124 #ifdef PRE_FILTER_MIN5
12125     if (!(PRE_FILTER_MIN5)) return;
12126 #endif
12127 
12128 #ifndef FIND_EXTENSIONS_MIN5
12129 #define FIND_EXTENSIONS_MIN5 find_extensions_min5
12130 #endif
12131 
12132     FIND_EXTENSIONS_MIN5(nbtot,nbop,extA1,extA2,&nextA,extB,extBmirror,
12133           &nextB,extC,&nextC,(nprevA==0?NULL:prevA[nprevA-1]));
12134 
12135     if (nextA > MAXN*MAXN/4)
12136     {
12137 	fprintf(stderr,">E Increase the array bounds for extA1 and\n");
12138 	fprintf(stderr,"   extA2 in scanmin5() and scanmin5c().\n");
12139 	exit(1);
12140     }
12141 
12142     for (i = 0; i < nextA; ++i)
12143     {
12144         extAred = extend_min5_a(extA1[i],extA2[i]);
12145 #ifdef FAST_FILTER_MIN5
12146         if (FAST_FILTER_MIN5)
12147 #endif
12148         {
12149 	    min5_a_legal(extAred,good_or,&ngood_or,&ngood_ref,
12150 		         good_mir,&ngood_mir,&ngood_mir_ref,prevA,nprevA);
12151 
12152             if (ngood_ref+ngood_mir_ref > 0)
12153 	    {
12154 	        if (nv == maxnv && !needgroup && ngood_or == ngood_ref
12155                                               && ngood_mir == ngood_mir_ref)
12156 	        {
12157 		    got_one(1,1,5);
12158 	        }
12159 	        else if (ngood_or+ngood_mir==1)
12160 	        {
12161 		    prevA[nprevA] = extAred;
12162     		    scanmin5c(1,1,nv==splitlevel,prevA,nprevA+1);
12163 	        }
12164 	        else if (canon_edge_oriented(good_or,ngood_or,ngood_ref,
12165                                            good_mir,ngood_mir,ngood_mir_ref,
12166                                            degree,numbering,&xnbtot,&xnbop))
12167 	        {
12168                     prevA[nprevA] = extAred;
12169 	            scanmin5c(xnbtot,xnbop,nv==splitlevel,prevA,nprevA+1);
12170 	        }
12171 	    }
12172 	}
12173 	reduce_min5_a(extAred);
12174     }
12175 
12176     for (i = 0; i < nextB; ++i)
12177     {
12178         extBred = extend_min5_b(extB[i],extBmirror[i]);
12179 #ifdef FAST_FILTER_MIN5
12180         if (FAST_FILTER_MIN5)
12181 #endif
12182         {
12183             if (!has_min5_a())
12184 	    {
12185                 min5_b_legal(extBred,extBmirror[i],good_or,&ngood_or,
12186 			     &ngood_ref,good_mir,&ngood_mir,&ngood_mir_ref);
12187 
12188                 if (ngood_ref+ngood_mir_ref > 0)
12189                 {
12190                     if (canon_edge_oriented(good_or,ngood_or,ngood_ref,
12191                                             good_mir,ngood_mir,ngood_mir_ref,
12192                                             degree,numbering,&xnbtot,&xnbop))
12193                         scanmin5c(xnbtot,xnbop,
12194                                   nv==splitlevel||nv==splitlevel+1,newprevA,0);
12195 	        }
12196 	    }
12197 	}
12198         reduce_min5_b(extBred,extBmirror[i]);
12199     }
12200 
12201     for (i = 0; i < nextC; ++i)
12202     {
12203         extCred = extend_min5_c(extC[i],&extCanchor);
12204 #ifdef FAST_FILTER_MIN5
12205         if (FAST_FILTER_MIN5)
12206 #endif
12207         {
12208             if (!has_min5_a() && !has_min5_b())
12209             {
12210 	        for (j = 0; j < nv-1; ++j)
12211 		    if (is_min5_c_centre(j)) colour[j] = 2;
12212 		    else                     colour[j] = degree[j];
12213 	        colour[nv-1] = 2;
12214 
12215                 if (canon(colour,numbering,&xnbtot,&xnbop))
12216                     scanmin5c(xnbtot,xnbop,
12217                               nv>=splitlevel&&nv<=splitlevel+4,newprevA,0);
12218             }
12219         }
12220         reduce_min5_c(extCred,extCanchor);
12221     }
12222 
12223     if (dosplit)
12224         for (i = 0; i < nv; ++i) firstedge[i] = firstedge_save[i];
12225 }
12226 
12227 /**************************************************************************/
12228 
12229 static int
wont_be_on_nf_3_cycle(EDGE * e)12230 wont_be_on_nf_3_cycle(EDGE *e)
12231 
12232 /* returns 1 if after switching e won't be on an nf 3-cycle. */
12233 
12234 {
12235   EDGE *run, *last, *dummy;
12236 
12237   RESETMARKS_V;
12238   dummy=e->next->invers;
12239   last=dummy->prev;
12240   run=dummy->next->next;
12241   MARK_V(run->end);
12242   while (run!=last)
12243     { run=run->next;
12244       MARK_V(run->end);
12245     }
12246 
12247   e=e->prev->invers;
12248   run=e->next;
12249   last=e->prev->prev;
12250   if (ISMARKED_V(run->end)) return 0;
12251   while (run!=last)
12252     { run=run->next;
12253       if (ISMARKED_V(run->end)) return 0;
12254     }
12255 
12256   return 1;
12257 }
12258 
12259 /*************************************************************************/
12260 
12261 static int
is_3banglecenter_notdouble(EDGE * e)12262 is_3banglecenter_notdouble(EDGE *e)
12263 
12264 /* returns 1 if it is the center of a 3bangle and after the edge is
12265    switched it is not in a double edge, 0 else */
12266 
12267 {
12268   EDGE *run, *last, *dummy;
12269   int end;
12270 
12271   RESETMARKS_V;
12272 
12273   dummy=e->next->invers;
12274   e=e->prev->invers;
12275   end=e->start;
12276 
12277   last=dummy->prev;
12278   run=dummy->next->next;
12279   if (run->end == end) return 0;
12280   MARK_V(run->end);
12281   while (run!=last)
12282     { run=run->next;
12283       if (run->end == end) return 0;
12284       MARK_V(run->end);
12285     }
12286 
12287   run=e->next;
12288   last=e->prev->prev;
12289   if (ISMARKED_V(run->end)) return 1;
12290   while (run!=last)
12291     { run=run->next;
12292       if (ISMARKED_V(run->end)) return 1;
12293     }
12294 
12295   return 0;
12296 }
12297 
12298 /***********************************************************************/
12299 
12300 static void
make_3bangle_list(EDGE * list[],int * listlength,EDGE * nf3cycleedges[],int numnf3cycleedges)12301 make_3bangle_list(EDGE *list[], int* listlength, EDGE *nf3cycleedges[],
12302                    int numnf3cycleedges)
12303 
12304 /* returns the list of legal 3-bangles, that is of (undirected) edges
12305    so that:
12306 
12307    (i) both endvertices have valency >=6
12308    (ii) it is not on an nf-3-cycle at the moment
12309    (iii) it is the center of a 3bangle
12310    (iv) after switching it is not in a double edge
12311 
12312    nf3cycleedges[] must be a list of all undirected edges -- that
12313    is: always containing edge->min lying on nf-3-cycles and
12314    numnf3cycleedges their number.
12315 */
12316 
12317 {
12318   int i, counter;
12319   EDGE *run, *end;
12320 
12321   RESETMARKS;
12322   while (--numnf3cycleedges >=0) MARKLO(nf3cycleedges[numnf3cycleedges]);
12323 
12324   counter=0;
12325 
12326   for (i=0; i<nv; i++)
12327     if (degree[i]>=6)
12328       { run=end=firstedge[i];
12329         do
12330           { if (run==run->min && degree[run->end]>=6
12331                   && !ISMARKEDLO(run) && is_3banglecenter_notdouble(run))
12332               { list[counter]=run; counter++; }
12333             run=run->next;
12334           }
12335         while (run != end);
12336       }
12337 
12338   *listlength=counter;
12339 }
12340 
12341 /**************************************************************************/
12342 
12343 static void
find_extensions_min5c3(int nbtot,int nbop,EDGE ** on4,int non4,EDGE ** on3,int non3,EDGE ** ext5_sw,int * next5_sw)12344 find_extensions_min5c3(int nbtot, int nbop, EDGE **on4, int non4,
12345                        EDGE **on3, int non3, EDGE **ext5_sw, int *next5_sw)
12346 
12347 /* List the inequivalent extensions for the 3-connected phase on mindeg 5.
12348    If on4!=NULL, it is a list of all edges on nf4-cycles (min form).
12349    If on3!=NULL, on3[0..non3-1] is a list of all edges on nf-3-cycles
12350    (min form).  If on3==NULL, there are no nf-3-cycles and non3==0.
12351    Exactly one of on4 and on3 is NULL.
12352 
12353    As a result, ext5_sw[0..*next5_sw-1] is set to all feasible switching
12354    operations.  Equivalent extensions are removed.
12355 */
12356 
12357 {
12358  /* Currently on4[] is not used, but we could use it if we wanted. */
12359     make_3bangle_list(ext5_sw,next5_sw,on3,non3);
12360 
12361     if (nbtot > 1 && *next5_sw > 1) prune_edgelist(ext5_sw,next5_sw,nbtot);
12362 }
12363 
12364 /**************************************************************************/
12365 
12366 static void
min5c3_sw_legal(EDGE * e,EDGE ** on3,int non3,EDGE ** good,int * ngood)12367 min5c3_sw_legal(EDGE *e, EDGE **on3, int non3, EDGE **good, int *ngood)
12368 
12369 /* Edge e (min form) has been switched (3-connected phase of mindeg=5).
12370    on3[0..non3-1] are all the edges in nf-3-cycles.
12371    Put into good[0..ngood-1] edges as desired for canon_edge().
12372 */
12373 
12374 #define SW53COL(e) (((long)degree[(e)->start] << 10) | (long)degree[(e)->end])
12375 {
12376     long bestcol,col;
12377     EDGE *e1,*e2;
12378     int i,ng;
12379 
12380     bestcol = SW53COL(e);
12381     col = SW53COL(e->invers);
12382     if (bestcol > col)
12383     {
12384         good[0] = e;
12385         ng = 1;
12386     }
12387     else if (bestcol == col)
12388     {
12389         good[0] = e;
12390         good[1] = e->invers;
12391         ng = 2;
12392     }
12393     else
12394     {
12395         good[0] = e->invers;
12396         ng = 1;
12397         bestcol = col;
12398     }
12399 
12400     for (i = 0; i < non3; ++i)
12401     {
12402         e1 = on3[i];
12403         e2 = e1->invers;
12404         if (degree[e1->start] >= 6 && degree[e1->end] >= 6 && e1 != e
12405                 && wont_be_on_nf_3_cycle(e1))
12406         {
12407             col = SW53COL(e1);
12408             if (col > bestcol)
12409             {
12410                 *ngood = 0;
12411                 return;
12412             }
12413             else if (col == bestcol)
12414                 good[ng++] = e1;
12415 
12416             col = SW53COL(e2);
12417             if (col > bestcol)
12418             {
12419                 *ngood = 0;
12420                 return;
12421             }
12422             else if (col == bestcol)
12423                 good[ng++] = e2;
12424         }
12425     }
12426 
12427     *ngood = ng;
12428 }
12429 
12430 /***********************************************************************/
12431 
12432 static void
add_new_nf3_cycles(EDGE * e,EDGE ** on3,int * non3)12433 add_new_nf3_cycles(EDGE *e, EDGE **on3, int *non3)
12434 
12435 /* The edge e has just been switched.  Previously it was not on any
12436    nf-3-cycles and on3[0..non3-1] was a list of all edges on nf-3-cycles.
12437    Add any new nf-3-cycles to on3[].  All edges are in min form. */
12438 
12439 {
12440     int i,j,k,v1;
12441     EDGE *e1,*e2,*ee;
12442     EDGE *e0[MAXN];
12443 
12444     RESETMARKS;
12445     for (i = *non3; --i >= 0; ) MARKLO(on3[i]);
12446 
12447     RESETMARKS_V;
12448     v1 = e->start;
12449     for (e1 = e->next->next, k = degree[v1]-3; --k >= 0; e1 = e1->next)
12450     {
12451         MARK_V(e1->end);
12452         e0[e1->end] = e1;
12453     }
12454 
12455     j = *non3;
12456     for (e1 = e->invers->next->next, k = degree[e->end]-3;
12457                                                    --k >= 0; e1 = e1->next)
12458         if (ISMARKED_V(e1->end))
12459         {
12460             e2 = e0[e1->end];
12461 
12462             ee = e->min;
12463             if (!ISMARKEDLO(ee))
12464             {
12465                 on3[j++] = ee;
12466                 MARKLO(ee);
12467             }
12468             ee = e1->min;
12469             if (!ISMARKEDLO(ee))
12470             {
12471                 on3[j++] = ee;
12472                 MARKLO(ee);
12473             }
12474             ee = e2->min;
12475             if (!ISMARKEDLO(ee))
12476             {
12477                 on3[j++] = ee;
12478                 MARKLO(ee);
12479             }
12480         }
12481     *non3 = j;
12482 }
12483 
12484 /**************************************************************************/
12485 
12486 static void
scanmin5c3_1(int nbtot,int nbop,EDGE ** on3,int non3)12487 scanmin5c3_1(int nbtot, int nbop, EDGE **on3, int non3)
12488 
12489 /* This is the first procedure that creates nf-3-cycles for mindeg=5
12490    triangulations.  It is called with a 3-connected triangulation and
12491    a list of the min forms of all the edges which lie on nf-3-cycles.
12492 */
12493 
12494 {
12495     EDGE *good[MAXE],*ext5_sw[MAXE/2];
12496     int i,xnbtot,xnbop,ngood,newnon3,next5_sw;
12497 
12498 #ifdef PRE_FILTER_MIN5c3
12499     if (!(PRE_FILTER_MIN5c3)) return;
12500 #endif
12501 
12502 #ifndef FIND_EXTENSIONS_MIN5c3
12503 #define FIND_EXTENSIONS_MIN5c3 find_extensions_min5c3
12504 #endif
12505 
12506     FIND_EXTENSIONS_MIN5c3(nbtot,nbop,NULL,0,on3,non3,ext5_sw,&next5_sw);
12507 
12508     if (pswitch) startpolyscan(nbtot,nbop);
12509     else         got_one(nbtot,nbop,3);
12510 
12511     for (i = 0; i < next5_sw; ++i)
12512     {
12513         switch_edge(ext5_sw[i]);
12514 #ifdef FAST_FILTER_MIN5c3
12515         if (FAST_FILTER_MIN5c3)
12516 #endif
12517         {
12518             newnon3 = non3;
12519             add_new_nf3_cycles(ext5_sw[i],on3,&newnon3);
12520 
12521             min5c3_sw_legal(ext5_sw[i],on3,newnon3,good,&ngood);
12522             if (ngood > 0
12523                     && canon_edge(good,ngood,degree,numbering,&xnbtot,&xnbop))
12524                 scanmin5c3_1(xnbtot,xnbop,on3,newnon3);
12525         }
12526         switch_edge_back(ext5_sw[i]);
12527     }
12528 }
12529 
12530 /**************************************************************************/
12531 
12532 static void
scanmin5c3_0(int nbtot,int nbop,EDGE ** on4,int non4)12533 scanmin5c3_0(int nbtot, int nbop, EDGE **on4, int non4)
12534 
12535 /* This is the first procedure that creates nf-3-cycles for mindeg=5
12536    triangulations.  It is called with a 4-connected triangulation and
12537    a list of the min forms of all the edges which lie on nf-4-cycles.
12538 */
12539 
12540 {
12541    EDGE *good[MAXE],*on3[MAXE/2];
12542    EDGE *ext5_sw[MAXE/2];
12543    int i,xnbtot,xnbop,ngood,non3,next5_sw;
12544 
12545 #ifdef PRE_FILTER_MIN5c3
12546     if (!(PRE_FILTER_MIN5c3)) return;
12547 #endif
12548 
12549 #ifndef FIND_EXTENSIONS_MIN5c3
12550 #define FIND_EXTENSIONS_MIN5c3 find_extensions_min5c3
12551 #endif
12552 
12553     FIND_EXTENSIONS_MIN5c3(nbtot,nbop,on4,non4,NULL,0,ext5_sw,&next5_sw);
12554 
12555     for (i = 0; i < next5_sw; ++i)
12556     {
12557         switch_edge(ext5_sw[i]);
12558 #ifdef FAST_FILTER_MIN5c3
12559         if (FAST_FILTER_MIN5c3)
12560 #endif
12561         {
12562             non3 = 0;
12563             add_new_nf3_cycles(ext5_sw[i],on3,&non3);
12564 
12565             min5c3_sw_legal(ext5_sw[i],on3,non3,good,&ngood);
12566             if (ngood > 0
12567                      && canon_edge(good,ngood,degree,numbering,&xnbtot,&xnbop))
12568                 scanmin5c3_1(xnbtot,xnbop,on3,non3);
12569 	}
12570         switch_edge_back(ext5_sw[i]);
12571     }
12572 }
12573 
12574 /**************************************************************************/
12575 
12576 static int
is_in_5_bangle(EDGE * e)12577 is_in_5_bangle(EDGE *e)
12578 
12579 /* Test if e is the central edge of a bangle, 5-connected case. */
12580 
12581 {
12582     EDGE *e1,*e2;
12583     int k,l;
12584 
12585     RESETMARKS_V;
12586     for (e1 = e->prev->invers->next->next, k = degree[e->prev->end]-4;
12587                                                  --k >= 0; e1 = e1->next)
12588         MARK_V(e1->end);
12589 
12590     for (e1 = e->next->invers->prev->prev, k = degree[e->next->end]-4;
12591                                                  --k >= 0; e1 = e1->prev)
12592         for (e2 = e1->invers->next->next, l = degree[e1->end]-3;
12593                                                  --l >= 0; e2 = e2->next)
12594             if (ISMARKED_V(e2->end)) return TRUE;
12595 
12596     return FALSE;
12597 }
12598 
12599 /**************************************************************************/
12600 
12601 static void
all_5_bangles(EDGE ** bang,int * nbang)12602 all_5_bangles(EDGE **bang, int *nbang)
12603 
12604 /* Set bang[0..nbang-1] to the central edges (min) of all bangles.
12605    5-connected case. */
12606 
12607 {
12608     int i,nb;
12609     EDGE *e,*elast;
12610 
12611     nb = 0;
12612     for (i = 0; i < nv; ++i)
12613     {
12614 	e = elast = firstedge[i];
12615 	do
12616 	{
12617 	    if (e == e->min && is_in_5_bangle(e)) bang[nb++] = e;
12618 	    e = e->next;
12619 	} while (e != elast);
12620     }
12621 
12622     *nbang = nb;
12623 }
12624 
12625 /**************************************************************************/
12626 
12627 static int
is_4bangle_centre(EDGE * e)12628 is_4bangle_centre(EDGE *e)
12629 
12630 /* returns TRUE if it is the center of a bangle, FALSE otherwise
12631    4-connected case of mindeg 5 */
12632 
12633 {
12634   EDGE *run, *run1, *last, *last1, *dummy;
12635 
12636 
12637   RESETMARKS_V;
12638 
12639   dummy=e->next->invers;
12640   last=dummy->prev;
12641   run=dummy->next->next;
12642   MARK_V(run->end);
12643   while (run!=last)
12644     { run=run->next;
12645       MARK_V(run->end);
12646     }
12647 
12648   e=e->prev->invers;
12649 
12650   run=e->next;
12651   last=e->prev->prev;
12652     dummy=run->invers;
12653     last1=dummy->prev->prev;
12654     run1=dummy->next->next;
12655     if (ISMARKED_V(run1->end)) return 1;
12656     run1=run1->next;
12657     if (ISMARKED_V(run1->end)) return 1;
12658     while (run1!=last1)
12659       { run1=run1->next; if (ISMARKED_V(run1->end)) return 1; }
12660   while (run!=last)
12661     { run=run->next;
12662       dummy=run->invers;
12663       last1=dummy->prev->prev;
12664       run1=dummy->next->next;
12665       if (ISMARKED_V(run1->end)) return 1;
12666       run1=run1->next;
12667       if (ISMARKED_V(run1->end)) return 1;
12668       while (run1!=last1)
12669         { run1=run1->next; if (ISMARKED_V(run1->end)) return 1; }
12670     }
12671 
12672   return 0;
12673 }
12674 
12675 /***********************************************************************/
12676 
12677 static int
will_be_on_nf_3_cycle(EDGE * e)12678 will_be_on_nf_3_cycle(EDGE *e)
12679 
12680 /* returns TRUE if after switching e will be on an nf-3-cycle, FALSE else.
12681    Assumes that there are no nf 3-cycles already and that the mins of all
12682    edges on nf-4-cycles are marked low. */
12683 
12684 {
12685   EDGE *run, *last, *dummy;
12686 
12687   if ((!ISMARKEDLO(e->next->min)) || (!ISMARKEDLO(e->prev->min))) return 0;
12688   /* If after switching it is on an nf-3-cycle, then they are on an nf-4-cycle
12689      already */
12690 
12691   RESETMARKS_V;
12692 
12693   dummy=e->next->invers;
12694   last=dummy->prev;
12695   run=dummy->next->next;
12696   MARK_V(run->end);
12697   while (run!=last)
12698     { run=run->next;
12699       MARK_V(run->end);
12700     }
12701 
12702   dummy=e->prev->invers;
12703 
12704   run=dummy->next;
12705   last=dummy->prev->prev;
12706 
12707   if (ISMARKED_V(run->end)) return 1;
12708   while (run!=last)
12709     { run=run->next;
12710       if (ISMARKED_V(run->end)) return 1;
12711     }
12712 
12713   return 0;
12714 }
12715 
12716 /***********************************************************************/
12717 
12718 static void
make_4bangle_list(EDGE * list[],int * listlength,EDGE * nf4cycleedges[],int numnf4cycleedges)12719 make_4bangle_list(EDGE *list[], int* listlength,
12720                   EDGE *nf4cycleedges[], int numnf4cycleedges)
12721 
12722 /* returns the list of legal 4-bangles, that is of (undirected) edges so that:
12723 
12724      (i) both endvertices have valency >=6
12725      (ii) it is not on an nf-4-cycle at the moment
12726      (iii) it is the center of a bangle
12727      (iv) after switching it is not on an nf-3-cycle
12728 
12729      It is assumed that there are no nf-3-cycles.
12730 
12731      nf4cycleedges[] must be a list of all undirected edges -- that
12732      is: always containing edge->min lying on nf-4-cycles and
12733      numnf4cycleedges their number.
12734 */
12735 
12736 {
12737   int i, counter;
12738   EDGE *run, *end;
12739 
12740   RESETMARKS;
12741   while (--numnf4cycleedges >= 0) MARKLO(nf4cycleedges[numnf4cycleedges]);
12742 
12743   counter=0;
12744 
12745   for (i=0; i<nv; i++)
12746     if (degree[i]>=6)
12747       { run=end=firstedge[i];
12748         do
12749           { if ((run==run->min) && (degree[run->end]>=6) && (!ISMARKEDLO(run))
12750                 && is_4bangle_centre(run) && (!will_be_on_nf_3_cycle(run)))
12751             { list[counter]=run; counter++; }
12752             run=run->next;
12753           }
12754         while (run != end);
12755       }
12756 
12757   *listlength=counter;
12758 
12759   return;
12760 }
12761 
12762 /***********************************************************************/
12763 
12764 static int
wont_be_on_nf_4_cycle(EDGE * e)12765 wont_be_on_nf_4_cycle(EDGE *e)
12766 
12767 /* returns 1 if after switching e won't be on an nf 4-cycle. Assumes that
12768    there are no nf 3-cycles either before or after the switching. */
12769 
12770 /* Alternative version:
12771 {
12772     EDGE *e1,*e2,*e3;
12773     int k1,k2,k3;
12774 
12775     RESETMARKS_V;
12776 
12777     for (e1 = e->prev->invers->next,
12778               k1 = degree[e1->start]-2; --k1 >= 0; e1 = e1->next)
12779 	MARK_V(e1->end);
12780 
12781     for (e2 = e->next->invers->prev,
12782               k2 = degree[e2->start]-2; --k2 >= 0; e2 = e2->prev)
12783 	for (e3 = e2->invers->next->next,
12784                   k3 = degree[e3->start]-3; --k3 >= 0; e3 = e3->next)
12785 	    if (ISMARKED_V(e3->end)) return FALSE;
12786 
12787     return TRUE;
12788 }
12789 */
12790 
12791 {
12792   EDGE *run, *run1, *last, *last1, *dummy;
12793 
12794   RESETMARKS_V;
12795   last=e->next->invers->prev;
12796   run=last->next->next->next;
12797   MARK_V(run->end);
12798   while (run!=last)
12799     { run=run->next;
12800       MARK_V(run->end);
12801     }
12802 
12803   e=e->prev->invers;
12804   run=e->next;
12805   last=e->prev->prev;
12806     dummy=run->invers;
12807     last1=dummy->prev->prev;
12808     run1=dummy->next->next;
12809     if (ISMARKED_V(run1->end)) return 0;
12810     run1=run1->next;
12811     if (ISMARKED_V(run1->end)) return 0;
12812     while (run1!=last1)
12813       { run1=run1->next; if (ISMARKED_V(run1->end)) return 0; }
12814   run=run->next;
12815     dummy=run->invers;
12816     last1=dummy->prev->prev;
12817     run1=dummy->next->next;
12818     if (ISMARKED_V(run1->end)) return 0;
12819     run1=run1->next;
12820     if (ISMARKED_V(run1->end)) return 0;
12821     while (run1!=last1)
12822       { run1=run1->next; if (ISMARKED_V(run1->end)) return 0; }
12823   while (run!=last)
12824     { run=run->next;
12825       dummy=run->invers;
12826       last1=dummy->prev->prev;
12827       run1=dummy->next->next;
12828       if (ISMARKED_V(run1->end)) return 0;
12829       run1=run1->next;
12830       if (ISMARKED_V(run1->end)) return 0;
12831       while (run1!=last1)
12832         { run1=run1->next; if (ISMARKED_V(run1->end)) return 0; }
12833     }
12834   return 1;
12835 }
12836 
12837 /***********************************************************************/
12838 
12839 static void
add_new_nf4_cycles(EDGE * e,EDGE ** on4,int * non4)12840 add_new_nf4_cycles(EDGE *e, EDGE **on4, int *non4)
12841 
12842 /* The edge e has just been switched.  Previously it was not on any
12843    nf-4-cycles and on4[0..non4-1] was a list of all edges on nf-4-cycles.
12844    Add any new nf-4-cycles to on4[].  All edges are in min form. */
12845 
12846 {
12847     int i,j,k,l,v1;
12848     EDGE *e1,*e2,*e3,*ee;
12849     EDGE *e0[MAXN];
12850 
12851     RESETMARKS;
12852     for (i = *non4; --i >= 0; ) MARKLO(on4[i]);
12853 
12854     RESETMARKS_V;
12855     v1 = e->start;
12856     for (e1 = e->next->next, k = degree[v1]-3; --k >= 0; e1 = e1->next)
12857     {
12858 	MARK_V(e1->end);
12859 	e0[e1->end] = e1;
12860     }
12861 
12862     j = *non4;
12863     for (e1 = e->invers->next->next, k = degree[e->end]-3;
12864 						   --k >= 0; e1 = e1->next)
12865 	for (e2 = e1->invers->next->next, l = degree[e1->end]-3;
12866                                                    --l >= 0; e2 = e2->next)
12867 	    if (ISMARKED_V(e2->end))
12868 	    {
12869 		e3 = e0[e2->end];
12870 
12871 		ee = e->min;
12872 		if (!ISMARKEDLO(ee))
12873 		{
12874 		    on4[j++] = ee;
12875 		    MARKLO(ee);
12876 		}
12877 		ee = e1->min;
12878 		if (!ISMARKEDLO(ee))
12879 		{
12880 		    on4[j++] = ee;
12881 		    MARKLO(ee);
12882 		}
12883 		ee = e2->min;
12884 		if (!ISMARKEDLO(ee))
12885 		{
12886 		    on4[j++] = ee;
12887 		    MARKLO(ee);
12888 		}
12889 		ee = e3->min;
12890 		if (!ISMARKEDLO(ee))
12891 		{
12892 		    on4[j++] = ee;
12893 		    MARKLO(ee);
12894 		}
12895 	    }
12896     *non4 = j;
12897 }
12898 
12899 /**************************************************************************/
12900 
12901 static int
common_5_endpoint(EDGE * e,EDGE * e1)12902 common_5_endpoint(EDGE *e, EDGE *e1)
12903 
12904 /* returns 1, if the endpoints of e and e1 have a common neighbour
12905    with valency 5, different from their start and different from
12906    e->prev->end, e->next->end, e1->prev->end, e1->next->end, 0 else.
12907    It is assumed that the starting points of e, e1 are the same, and that
12908 
12909 */
12910 
12911 /*  Alternate version:
12912 {
12913     EDGE *ee;
12914     int k;
12915 
12916     RESETMARKS_V;
12917 
12918     ee = e->invers->next->next;
12919     for (k = degree[ee->start]-3; --k >= 0; ee = ee->next)
12920 	if (degree[ee->end] == 5) MARK_V(ee->end);
12921 
12922     ee = e1->invers->next->next;
12923     for (k = degree[ee->start]-3; --k >= 0; ee = ee->next)
12924         if (ISMARKED_V(ee->end)) return TRUE;
12925 
12926     return FALSE;
12927 }
12928 */
12929 
12930 {
12931   EDGE *run, *last;
12932 
12933   RESETMARKS_V;
12934 
12935   e=e->invers; e1=e1->invers;
12936 
12937   run=e->next->next;
12938   if (degree[run->end]==5) MARK_V(run->end);
12939   run=run->next;
12940   if (degree[run->end]==5) MARK_V(run->end);
12941   last=e->prev->prev;
12942   while (run!=last)
12943     { run=run->next;
12944     if (degree[run->end]==5) MARK_V(run->end);
12945     }
12946 
12947   run=e1->next->next;
12948   if (ISMARKED_V(run->end)) return 1;
12949   run=run->next;
12950   if (ISMARKED_V(run->end)) return 1;
12951   last=e1->prev->prev;
12952   while (run!=last)
12953     { run=run->next;
12954     if (ISMARKED_V(run->end)) return 1;
12955     }
12956   return 0;
12957 }
12958 
12959 /**************************************************************************/
12960 
12961 static void
make_5exp_list(EDGE * list1[],EDGE * list2[],int * listlength,EDGE * nf4cycleedges[],int numnf4cycleedges)12962 make_5exp_list(EDGE *list1[], EDGE *list2[], int *listlength,
12963                EDGE *nf4cycleedges[], int numnf4cycleedges)
12964 
12965 /* returns the list of legal 5-expansions for the mindeg5 4-connectivity
12966    case, that is of (undirected) pairs of edges so that:
12967 
12968    (i) both edges start at the same point of valency >=6
12969    (ii) in between them there are (on one side) exactly two edges and
12970         these are not on an nf-4-cycle
12971    (iii) their endpoints have a common neighbour of valency 5 (so
12972          especially both edges must be on an nf-4-cycle)
12973 
12974    The list comes in pairs of two, that is: for 0<=i<*listlength
12975    list1[i] and list2[i] belong together.
12976 
12977    It is assumed that there are no nf-3-cycles.
12978 
12979    nf4cycleedges[] must be a list of all undirected edges -- that
12980    is: always containing edge->min lying on nf-4-cycles and
12981    numnf4cycleedges their number.
12982 */
12983 
12984 {
12985   int i, counter;
12986   EDGE *run, *run1, *end;
12987 
12988   RESETMARKS;
12989   for (i = numnf4cycleedges; --i >= 0; )
12990     { MARKLO(nf4cycleedges[i]); MARKLO(nf4cycleedges[i]->invers); }
12991 
12992   counter=0;
12993 
12994   for (i=0; i<nv; i++)
12995     if (degree[i]>=6)
12996       { run=firstedge[i];
12997       if (degree[i]==6)
12998         /* This case is special, since for opposite edges, the "same" expansion
12999            would be done, but different edges would be ckecked to judge whether
13000            it is legal. If deg>6 there is a 1-1 correspondence between the two
13001            edges in between and the expansion edgepair */
13002         { end=run->next->next->next;
13003         do
13004           {
13005             if (ISMARKEDLO(run))
13006               { run1=run->next->next->next;
13007               /* is done inside the loop and not as a second run variable,
13008                  since most likely the loop is entered not too often, so
13009                  that in those rare cases where it is entered, it pays off
13010                  to have three "nexts". */
13011               if (ISMARKEDLO(run1) &&
13012                   ((!ISMARKEDLO(run->next) && !ISMARKEDLO(run1->prev)) ||
13013                    (!ISMARKEDLO(run1->next) && !ISMARKEDLO(run->prev))))
13014                 if (common_5_endpoint(run,run1))
13015                   { list1[counter]=run;
13016                     list2[counter]=run1; counter++; }
13017               }
13018             run=run->next;
13019           }
13020         while (run != end);
13021         }
13022 
13023       else /* degree > 6 */
13024         { end=run;
13025         do
13026           {
13027             if (ISMARKEDLO(run))
13028               { run1=run->next->next->next;
13029               if (ISMARKEDLO(run1) &&
13030                   (!ISMARKEDLO(run->next) && !ISMARKEDLO(run1->prev)))
13031                 if (common_5_endpoint(run,run1))
13032                   { list1[counter]=run;
13033                     list2[counter]=run1; counter++; }
13034               }
13035             run=run->next;
13036           }
13037         while (run != end);
13038         } /*else deg>6 */
13039       }/* end deg>=6 */
13040 
13041   *listlength=counter;
13042 
13043   return;
13044 }
13045 
13046 /**************************************************************************/
13047 
13048 static void
find_extensions_min5c4(int nbtot,int nbop,EDGE ** bang,int nbang,EDGE ** on4,int non4,EDGE ** ext5_sw,int * next5_sw,EDGE ** ext5_51,EDGE ** ext5_52,int * next5_5)13049 find_extensions_min5c4(int nbtot, int nbop, EDGE **bang, int nbang,
13050                        EDGE **on4, int non4, EDGE **ext5_sw, int *next5_sw,
13051                        EDGE **ext5_51, EDGE **ext5_52, int *next5_5)
13052 
13053 /* List the inequivalent extensions for the 4-connected phase on mindeg 5.
13054    If bang!=NULL, it is a list of all bangles perhaps with some of
13055    insufficient degree.  If on4!=NULL, on4[0..non4-1] is a list of all edges
13056    on nf-4-cycles (min form).  If on4==NULL, there are no nf-4-cycles and
13057    non4=0.  Exactly one of bang and on4 is NULL.
13058 
13059    As a result, ext5_sw[0..*next5_sw-1] is set to all feasible switching
13060    operations, and (ext5_51,ext5_52)[0..*next5_5-1] is set to all feasible
13061    5-expansions as pairs of edges.  Equivalent extensions are removed.
13062 */
13063 
13064 {
13065     int i,k;
13066     EDGE *e1,*e2,**nb0,**nblim,**nb1,**nb2;
13067 
13068     k = 0;
13069     if (bang)
13070     {
13071         for (i = 0; i < nbang; ++i)
13072 	    if (degree[bang[i]->start] >= 6 && degree[bang[i]->end] >= 6)
13073 		ext5_sw[k++] = bang[i];
13074     }
13075     else
13076 	make_4bangle_list(ext5_sw,&k,on4,non4);
13077 
13078     if (nbtot > 1 && k > 1) prune_edgelist(ext5_sw,&k,nbtot);
13079 
13080     *next5_sw = k;
13081 
13082     if (nv < maxnv && on4 && non4 >= 6)
13083     {
13084 	make_5exp_list(ext5_51,ext5_52,next5_5,on4,non4);
13085 
13086 	if (nbtot == 1 || *next5_5 <= 1) return;
13087 
13088         nb0 = (EDGE**)numbering[0];
13089         nblim = (EDGE**)numbering[nbtot];
13090 
13091         for (i = 0; i < ne; ++i) nb0[i]->index = i;
13092 
13093 	k = 0;
13094 	for (i = 0; i < *next5_5; ++i)
13095 	{
13096 	    if (ext5_51[i] < ext5_52[i]) { e1 = ext5_51[i]; e2 = ext5_52[i]; }
13097 	    else                         { e1 = ext5_52[i]; e2 = ext5_51[i]; }
13098 
13099 	    nb1 = &nb0[e1->index + MAXE];
13100             nb2 = &nb0[e2->index + MAXE];
13101             for ( ; nb1 < nblim; nb1 += MAXE, nb2 += MAXE)
13102                 if (*nb1 < *nb2)
13103                 {
13104                     if (*nb1 < e1 || (*nb1 == e1 && *nb2 < e2)) break;
13105                 }
13106                 else
13107                 {
13108                     if (*nb2 < e1 || (*nb2 == e1 && *nb1 < e2)) break;
13109                 }
13110 
13111             if (nb1 >= nblim)
13112             {
13113                 ext5_51[k] = e1;
13114                 ext5_52[k] = e2;
13115                 ++k;
13116             }
13117 	}
13118 	*next5_5 = k;
13119     }
13120     else
13121         *next5_5 = 0;
13122 }
13123 
13124 /**************************************************************************/
13125 
13126 static void
min5c4_sw_legal(EDGE * e,EDGE ** on4,int non4,EDGE ** good,int * ngood)13127 min5c4_sw_legal(EDGE *e, EDGE **on4, int non4, EDGE **good, int *ngood)
13128 
13129 /* Edge e (min form) has been switched (4-connected phase of mindeg=5).
13130    on4[0..non4-1] are all the edges in nf-4-cycles.
13131    Put into good[0..ngood-1] edges as desired for canon_edge().
13132 */
13133 
13134 #define BANGCOL(e) (((long)degree[(e)->start] << 10) | (long)degree[(e)->end])
13135 #define BANGCOL2(e) (degree[(e)->next->end] + degree[(e)->prev->end])
13136 {
13137     long bestcol,col;
13138     int bestcol2,col2;
13139     EDGE *e1,*e2;
13140     int i,ng;
13141 
13142     bestcol = BANGCOL(e);
13143     col = BANGCOL(e->invers);
13144     bestcol2 = BANGCOL2(e);
13145 
13146     if (bestcol > col)
13147     {
13148 	good[0] = e;
13149 	ng = 1;
13150     }
13151     else if (bestcol == col)
13152     {
13153 	good[0] = e;
13154 	good[1] = e->invers;
13155 	ng = 2;
13156     }
13157     else
13158     {
13159 	good[0] = e->invers;
13160 	ng = 1;
13161 	bestcol = col;
13162     }
13163 
13164     for (i = 0; i < non4; ++i)
13165     {
13166 	e1 = on4[i];
13167 	e2 = e1->invers;
13168 	if (degree[e1->start] >= 6 && degree[e1->end] >= 6 && e1 != e
13169 		&& wont_be_on_nf_4_cycle(e1))
13170 	{
13171 	    col2 = BANGCOL2(e1);
13172 
13173 	    col = BANGCOL(e1);
13174 	    if (col > bestcol)
13175 	    {
13176 		*ngood = 0;
13177 		return;
13178 	    }
13179 	    else if (col == bestcol)
13180 	    {
13181 		if (col2 > bestcol2)
13182 		{
13183                     *ngood = 0;
13184                     return;
13185                 }
13186 		else if (col2 == bestcol2)
13187 	            good[ng++] = e1;
13188 	    }
13189 
13190 	    col = BANGCOL(e2);
13191 	    if (col > bestcol)
13192 	    {
13193 		*ngood = 0;
13194 		return;
13195 	    }
13196 	    else if (col == bestcol)
13197             {
13198                 if (col2 > bestcol2)
13199                 {
13200                     *ngood = 0;
13201                     return;
13202                 }
13203                 else if (col2 == bestcol2)
13204                     good[ng++] = e2;
13205             }
13206 	}
13207     }
13208 
13209     *ngood = ng;
13210 }
13211 
13212 /**************************************************************************/
13213 
13214 static int
has_min5c4_sw(EDGE ** on4,int non4)13215 has_min5c4_sw(EDGE **on4, int non4)
13216 
13217 /* on4[0..non4-1] is a complete list of all (min) edges in nf-4-cycles.
13218    Return TRUE if there is a valid switch-reduction.  Assume no nf-3-cycles.
13219 */
13220 
13221 {
13222     EDGE *e;
13223     int i;
13224 
13225     for (i = 0; i < non4; ++i)
13226     {
13227 	e = on4[i];
13228 
13229 	if (degree[e->start] >= 6 && degree[e->end] >= 6
13230             				    && wont_be_on_nf_4_cycle(e))
13231 	    return TRUE;
13232     }
13233 
13234     return FALSE;
13235 }
13236 
13237 /**************************************************************************/
13238 
13239 static int
will_be_on_nf4_5red(EDGE * e)13240 will_be_on_nf4_5red(EDGE *e)
13241 
13242 /* Checks whether performing a 5-reduction at e (e starting at the
13243    vertex with valency 5) will produce a configuration with
13244    one of the diagonals being on an nf-4-cycle. It is assumed
13245    that it is already assured that a 5-reduction here is possible
13246    (e.g. degree[e->start]=5).
13247 
13248    It somehow simulates the situation after the switch. This is
13249    a bit ugly, since after the switch on ONE side there will be
13250    an additional edge and on the other there won't.
13251 */
13252 
13253 {
13254   EDGE *run, *run1, *last, *last1, *dummy, *e1, *e2;
13255 
13256   /* It is important for the correctness, that we go ONE step from e and
13257      two from e1, resp e2 */
13258 
13259   e1=e->prev->prev->invers; e2=e->next->next->invers;
13260   e=e->invers;
13261 
13262   RESETMARKS_V;
13263   last=e->prev; /* there will be an edge in between */
13264   run=e->next->next;
13265   MARK_V(run->end);
13266   while (run!=last)
13267     { run=run->next;
13268       MARK_V(run->end);
13269     }
13270 
13271   last=e1->prev->prev; /* I cannot reach the edges that will be
13272 			  missing after the reduction in two steps, so
13273 			  here I can proceed "as usual" */
13274   run=e1->next->next;
13275   dummy=run->invers;
13276   last1=dummy->prev->prev;
13277   run1=dummy->next->next;
13278   if (ISMARKED_V(run1->end)) return 1;
13279   run1=run1->next;
13280   if (ISMARKED_V(run1->end)) return 1;
13281   while (run1!=last1) { run1=run1->next; if (ISMARKED_V(run1->end)) return 1; }
13282   run=run->next;
13283   dummy=run->invers;
13284   last1=dummy->prev->prev;
13285   run1=dummy->next->next;
13286   if (ISMARKED_V(run1->end)) return 1;
13287   run1=run1->next;
13288   if (ISMARKED_V(run1->end)) return 1;
13289   while (run1!=last1) { run1=run1->next; if (ISMARKED_V(run1->end)) return 1; }
13290   while (run!=last)
13291     { run=run->next;
13292       dummy=run->invers;
13293       last1=dummy->prev->prev;
13294       run1=dummy->next->next;
13295       if (ISMARKED_V(run1->end)) return 1;
13296       run1=run1->next;
13297       if (ISMARKED_V(run1->end)) return 1;
13298       while (run1!=last1)
13299         { run1=run1->next; if (ISMARKED_V(run1->end)) return 1; }
13300     }
13301 
13302   RESETMARKS_V;
13303   last=e->prev->prev;
13304   run=e->next; /* there will be an edge in between */
13305   MARK_V(run->end);
13306   while (run!=last)
13307     { run=run->next;
13308       MARK_V(run->end);
13309     }
13310 
13311   last=e2->prev->prev; /* I cannot reach the edges that will be
13312                           missing after the reduction in two steps,
13313 			  so here I can proceed "as usual" */
13314   run=e2->next->next;
13315   dummy=run->invers;
13316   last1=dummy->prev->prev;
13317   run1=dummy->next->next;
13318   if (ISMARKED_V(run1->end)) return 1;
13319   run1=run1->next;
13320   if (ISMARKED_V(run1->end)) return 1;
13321   while (run1!=last1) { run1=run1->next; if (ISMARKED_V(run1->end)) return 1; }
13322   run=run->next;
13323   dummy=run->invers;
13324   last1=dummy->prev->prev;
13325   run1=dummy->next->next;
13326   if (ISMARKED_V(run1->end)) return 1;
13327   run1=run1->next;
13328   if (ISMARKED_V(run1->end)) return 1;
13329   while (run1!=last1) { run1=run1->next; if (ISMARKED_V(run1->end)) return 1; }
13330   while (run!=last)
13331     { run=run->next;
13332       dummy=run->invers;
13333       last1=dummy->prev->prev;
13334       run1=dummy->next->next;
13335       if (ISMARKED_V(run1->end)) return 1;
13336       run1=run1->next;
13337       if (ISMARKED_V(run1->end)) return 1;
13338       while (run1!=last1)
13339         { run1=run1->next; if (ISMARKED_V(run1->end)) return 1; }
13340     }
13341 
13342   return 0;
13343 }
13344 
13345 /***********************************************************************/
13346 
13347 static int
legal_5_min5_reduction(EDGE * e,EDGE * nf4cycleedges[],int numnf4cycleedges)13348 legal_5_min5_reduction(EDGE *e, EDGE *nf4cycleedges[], int numnf4cycleedges)
13349 
13350 /* Checks whether the edge given is a legal reference edge for a 5-reduction
13351    in the minimum valency 5 connectivity 4 case, that is:
13352 
13353    (i) e->start has degree 5 (note that this way in case of both
13354         endpoints valency 5 the routine has to be called for e and
13355         e->invers due to the asymmetric behaviour of (iii))
13356    (ii) The two endpoints of e->next, e->prev have valency at least 6
13357    (iii) The two endpoints of e->next, e->prev have a common neighbour with
13358          valency 5 different from e->start, e->end, so especially
13359          e->next, e->prev, e->invers->next, e->invers->prev all are on
13360          nf-4-cycles.
13361   (iv) after doing the 5-reduction e->next->next and e->prev->prev
13362        will not be on 4-cycles
13363 
13364    Returns 1 in case it is a legal reduction, 0 otherwise. Assumes the
13365    non-existence of nf-3-cycles.  nf4cycleedges[0..numnf4cycleedges-1]
13366    are the min forms of all edges on nf-4-cycles.
13367 */
13368 
13369 {
13370   EDGE *dummy;
13371 
13372   if (degree[e->start]!=5) return 0;
13373 
13374   RESETMARKS;
13375   for (numnf4cycleedges--; numnf4cycleedges>=0; numnf4cycleedges--)
13376     MARKLO(nf4cycleedges[numnf4cycleedges]);
13377 
13378   if (!ISMARKEDLO(e->next->min) || !ISMARKEDLO(e->prev->min)) return 0;
13379   dummy=e->invers;
13380   if (!ISMARKEDLO(dummy->next->min) || !ISMARKEDLO(dummy->prev->min)) return 0;
13381   if (!common_5_endpoint(e->next,e->prev)) return 0;
13382   if (will_be_on_nf4_5red(e)) return 0;
13383 
13384   return 1;
13385 }
13386 
13387 /**************************************************************************/
13388 
13389 static void
min5c4_5_legal(EDGE * ref,EDGE ** on4,int non4,EDGE ** good,int * ngood)13390 min5c4_5_legal(EDGE *ref, EDGE **on4, int non4, EDGE **good, int *ngood)
13391 
13392 /* e is the reference edge of a min5-5-expansion that has just been done.
13393    on4[0..non4-1] are the min forms of all edges on nf-4-cycles.
13394    There are no nf-3-cycles.
13395    Create in good[0..*ngood-1] a list of directed edges in the form
13396    required by canon_edge().
13397 */
13398 
13399 {
13400     long bestdeg;
13401     EDGE *e,*elast;
13402     int i,ng;
13403 
13404     ng = 0;
13405     if (legal_5_min5_reduction(ref,on4,non4)) good[ng++] = ref;
13406     if (legal_5_min5_reduction(ref->invers,on4,non4)) good[ng++] = ref->invers;
13407 
13408     bestdeg = MAX(degree[ref->start],degree[ref->end]);
13409 
13410     for (i = 0; i < nv; ++i)
13411     if (degree[i] == 5)
13412     {
13413 	e = elast = firstedge[i];
13414 	do
13415 	{
13416 	    if (degree[e->end] >= bestdeg && e != ref && e != ref->invers
13417                                          && legal_5_min5_reduction(e,on4,non4))
13418 	    {
13419 		if (degree[e->end] > bestdeg)
13420 		{
13421 		    *ngood = 0;
13422 		    return;
13423 		}
13424 		else
13425 		    good[ng++] = e;
13426 	    }
13427 	    e = e->next;
13428 	} while (e != elast);
13429     }
13430 
13431     *ngood = ng;
13432 }
13433 
13434 /**************************************************************************/
13435 
13436 static void
scanmin5c4_1(int nbtot,int nbop,EDGE ** on4,int non4)13437 scanmin5c4_1(int nbtot, int nbop, EDGE **on4, int non4)
13438 
13439 /* This is the recursive procedure that creates nf-4-cycles for mindeg=5
13440    triangulations.  The first call is with a 4-connected triangulation
13441    made by a single switching from a 5-connected triangulation.
13442    on4[0..non4-1] are all edges on nf-4-cycles (min form).
13443 */
13444 
13445 {
13446     EDGE *good[MAXE],*extAred;
13447     EDGE *ext5_sw[MAXE/2],*ext5_51[MAXE],*ext5_52[MAXE];
13448     int next5_sw,next5_5;
13449     int newnon4,i,xnbtot,xnbop,ngood;
13450 
13451 #ifdef PRE_FILTER_MIN5c4
13452     if (!(PRE_FILTER_MIN5c4)) return;
13453 #endif
13454 
13455 #ifndef FIND_EXTENSIONS_MIN5c4
13456 #define FIND_EXTENSIONS_MIN5c4 find_extensions_min5c4
13457 #endif
13458 
13459     FIND_EXTENSIONS_MIN5c4(nbtot,nbop,NULL,0,on4,non4,
13460 	       		   ext5_sw,&next5_sw,ext5_51,ext5_52,&next5_5);
13461 
13462     if (nv == maxnv)
13463     {
13464 	if (pswitch) startpolyscan(nbtot,nbop);   /* Saves the group! */
13465         else         got_one(nbtot,nbop,4);
13466 
13467 	if (minconnec < 4 && non4 >= 6) scanmin5c3_0(nbtot,nbop,on4,non4);
13468     }
13469 
13470     for (i = 0; i < next5_sw; ++i)
13471     {
13472 	switch_edge(ext5_sw[i]);
13473 #ifdef FAST_FILTER_MIN5c4
13474         if (FAST_FILTER_MIN5c4)
13475 #endif
13476         {
13477 	    newnon4 = non4;
13478 	    add_new_nf4_cycles(ext5_sw[i],on4,&newnon4);
13479 
13480 	    min5c4_sw_legal(ext5_sw[i],on4,newnon4,good,&ngood);
13481 	    if (ngood > 0
13482 		      && canon_edge(good,ngood,degree,numbering,&xnbtot,&xnbop))
13483 	        scanmin5c4_1(xnbtot,xnbop,on4,newnon4);
13484 	}
13485 	switch_edge_back(ext5_sw[i]);
13486     }
13487 
13488     for (i = 0; i < next5_5; ++i)
13489     {
13490 	extAred = extend_min5_a(ext5_51[i],ext5_52[i]);
13491 #ifdef FAST_FILTER_MIN5c4
13492         if (FAST_FILTER_MIN5c4)
13493 #endif
13494         {
13495 	    if (extAred->start == nv-1)
13496 	    {
13497 	        on4[non4] = extAred->next->min;
13498 	        on4[non4+1] = extAred->prev->min;
13499 	        newnon4 = non4 + 2;
13500 	    }
13501 	    else
13502 	    {
13503 	        on4[non4] = extAred->invers->next->min;
13504 	        on4[non4+1] = extAred->invers->prev->min;
13505 	        newnon4 = non4 + 2;
13506 	    }
13507 
13508 	    if (!has_min5c4_sw(on4,newnon4))
13509 	    {
13510 	        min5c4_5_legal(extAred,on4,newnon4,good,&ngood);
13511 	        if (ngood > 0
13512                      && canon_edge(good,ngood,degree,numbering,&xnbtot,&xnbop))
13513 	            scanmin5c4_1(xnbtot,xnbop,on4,newnon4);
13514 	    }
13515 	}
13516 	reduce_min5_a(extAred);
13517     }
13518 }
13519 
13520 /**************************************************************************/
13521 
13522 static void
scanmin5c4_0(int nbtot,int nbop,EDGE ** bang,int nbang)13523 scanmin5c4_0(int nbtot, int nbop, EDGE **bang, int nbang)
13524 
13525 /* This is the first procedure that creates nf-4-cycles for mindeg=5
13526    triangulations.  It is called with a 5-connected triangulation.
13527    bang[0..nbang-1] are all proper bangles and possibly some improper
13528    bangles (degree 5 at one or both ends).  For this first step, only
13529    a switching operation is possible.
13530 */
13531 
13532 {
13533     EDGE *good[MAXE],*on4[MAXE/2];
13534     EDGE *ext5_sw[MAXE/2],*ext5_51[1],*ext5_52[1]; /* 5-expansion impossible */
13535     int next5_sw,next5_5;
13536     int i,xnbtot,xnbop,ngood,non4;
13537     EDGE *firstedge_save[MAXN];
13538 
13539     if (nv < splitlevel && res > 0) return;
13540 
13541     if (splitlevel > 0)
13542 	for (i = 0; i < nv; ++i) firstedge_save[i] = firstedge[i];
13543 
13544 #ifdef PRE_FILTER_MIN5c4
13545     if (!(PRE_FILTER_MIN5c4)) return;
13546 #endif
13547 
13548 #ifndef FIND_EXTENSIONS_MIN5c4
13549 #define FIND_EXTENSIONS_MIN5c4 find_extensions_min5c4
13550 #endif
13551 
13552     FIND_EXTENSIONS_MIN5c4(nbtot,nbop,bang,nbang,NULL,0,
13553 			          ext5_sw,&next5_sw,ext5_51,ext5_52,&next5_5);
13554 
13555     for (i = 0; i < next5_sw; ++i)
13556     {
13557 	switch_edge(ext5_sw[i]);
13558 #ifdef FAST_FILTER_MIN5c4
13559         if (FAST_FILTER_MIN5c4)
13560 #endif
13561         {
13562 	    non4 = 0;
13563 	    add_new_nf4_cycles(ext5_sw[i],on4,&non4);
13564 
13565 	    min5c4_sw_legal(ext5_sw[i],on4,non4,good,&ngood);
13566 	    if (ngood > 0
13567 		     && canon_edge(good,ngood,degree,numbering,&xnbtot,&xnbop))
13568 	        scanmin5c4_1(xnbtot,xnbop,on4,non4);
13569 	}
13570 	switch_edge_back(ext5_sw[i]);
13571     }
13572 
13573     if (splitlevel > 0)
13574 	for (i = 0; i < nv; ++i) firstedge[i] = firstedge_save[i];
13575 }
13576 
13577 /**************************************************************************/
13578 
13579 static void
scanmin5(int nbtot,int nbop,int dosplit,EDGE ** prevA,int nprevA,EDGE ** bangle,int nbangles)13580 scanmin5(int nbtot, int nbop, int dosplit, EDGE **prevA, int nprevA,
13581          EDGE **bangle, int nbangles)
13582 
13583 /* The main node of the recursion for triangulations with minimum
13584    degree 5, connectivity 3 or 4.  This part of the recursion makes
13585    5-connected triangulations.
13586    As this procedure is entered, nv,ne,degree etc are set for some graph,
13587    and nbtot/nbop are the values returned by canon() for that graph.
13588    If dosplit==TRUE, this is the place to do splitting (if any).
13589    prev[0..nprevA-1] is the list of consecutive A operations leading
13590    to this graph, given by their central edges.
13591    If nprevA == 0, this graph wasn't made with A.
13592    bangle[0..nbangles-1] contains the edges which are central
13593    edges of a bangle.
13594 */
13595 
13596 {
13597     EDGE *firstedge_save[MAXN];
13598     EDGE *extA1[MAXN*MAXN/4+10],*extA2[MAXN*MAXN/4+10],
13599          *extB[MAXE],*extC[MAXN];
13600     EDGE *extAred,*extBred,*extCred,*extCanchor;
13601     int extBmirror[MAXE];
13602     EDGE *good_or[MAXE],*good_mir[MAXE];
13603     EDGE *newprevA[MAXN];
13604     EDGE *newbang[MAXE/2];
13605     int newnbang;
13606     int ngood_or,ngood_mir,ngood_ref,ngood_mir_ref;
13607     int nextA,nextB,nextC,i,j,k;
13608     int xnbtot,xnbop;
13609     int colour[MAXN];
13610 
13611     if (nv == maxnv)
13612     {
13613 	if (pswitch) startpolyscan(nbtot,nbop);   /* Saves the group! */
13614         else         got_one(nbtot,nbop,5);
13615         if (nbangles > 0) scanmin5c4_0(nbtot,nbop,bangle,nbangles);
13616 	return;
13617     }
13618 
13619     if (dosplit)
13620     {
13621 #ifdef SPLITTEST
13622         ++splitcases;
13623         return;
13624 #endif
13625         if (splitcount-- != 0) return;
13626         splitcount = mod - 1;
13627 
13628         for (i = 0; i < nv; ++i) firstedge_save[i] = firstedge[i];
13629     }
13630 
13631 #ifdef PRE_FILTER_MIN5
13632     if (!(PRE_FILTER_MIN5)) return;
13633 #endif
13634 
13635 #ifndef FIND_EXTENSIONS_MIN5
13636 #define FIND_EXTENSIONS_MIN5 find_extensions_min5
13637 #endif
13638 
13639     FIND_EXTENSIONS_MIN5(nbtot,nbop,extA1,extA2,&nextA,extB,extBmirror,
13640           &nextB,extC,&nextC,(nprevA==0?NULL:prevA[nprevA-1]));
13641 
13642     if (nbangles > 0) scanmin5c4_0(nbtot,nbop,bangle,nbangles);
13643 
13644     for (i = 0; i < nextA; ++i)
13645     {
13646         extAred = extend_min5_a(extA1[i],extA2[i]);
13647 #ifdef FAST_FILTER_MIN5
13648         if (FAST_FILTER_MIN5)
13649 #endif
13650         {
13651 	    min5_a_legal(extAred,good_or,&ngood_or,&ngood_ref,
13652 		         good_mir,&ngood_mir,&ngood_mir_ref,prevA,nprevA);
13653 
13654             if (ngood_ref+ngood_mir_ref > 0)
13655 	    {
13656 	        newnbang = 0;
13657 	        for (j = 0; j < nbangles; ++j)
13658 		    if (is_in_5_bangle(bangle[j]))
13659 			newbang[newnbang++] = bangle[j];
13660 	        if (is_in_5_bangle(extAred)) newbang[newnbang++] = extAred;
13661 
13662 	        if (nv == maxnv)
13663 	        {
13664 	            k = 0;
13665 	            for (j = 0; j < newnbang; ++j)
13666 		        if (degree[newbang[j]->start] >= 6
13667                                               && degree[newbang[j]->end] >= 6)
13668 			    newbang[k++] = newbang[j];
13669 		    newnbang = k;
13670 	        }
13671 
13672                 if (nv == maxnv && !needgroup && ngood_or == ngood_ref
13673                                               && ngood_mir == ngood_mir_ref
13674                                               && ((newnbang == 0 && minconnec == 4)
13675 		  			            || minconnec == 5))
13676 	        {
13677                     got_one(1,1,5);   /* Note: -p implies -G */
13678 	        }
13679                 else if (ngood_or+ngood_mir==1)
13680                 {
13681                     prevA[nprevA] = extAred;
13682                     scanmin5(1,1,nv==splitlevel,prevA,nprevA+1,
13683 							newbang,newnbang);
13684                 }
13685                 else if (canon_edge_oriented(good_or,ngood_or,ngood_ref,
13686                                            good_mir,ngood_mir,ngood_mir_ref,
13687                                            degree,numbering,&xnbtot,&xnbop))
13688                 {
13689                     prevA[nprevA] = extAred;
13690                     scanmin5(xnbtot,xnbop,nv==splitlevel,
13691                              prevA,nprevA+1,newbang,newnbang);
13692                 }
13693 	    }
13694 	}
13695 	reduce_min5_a(extAred);
13696     }
13697 
13698     for (i = 0; i < nextB; ++i)
13699     {
13700         extBred = extend_min5_b(extB[i],extBmirror[i]);
13701 #ifdef FAST_FILTER_MIN5
13702         if (FAST_FILTER_MIN5)
13703 #endif
13704         {
13705             if (!has_min5_a())
13706 	    {
13707                 min5_b_legal(extBred,extBmirror[i],good_or,&ngood_or,
13708 			     &ngood_ref,good_mir,&ngood_mir,&ngood_mir_ref);
13709 
13710                 if (ngood_ref+ngood_mir_ref > 0)
13711                 {
13712                     if (canon_edge_oriented(good_or,ngood_or,ngood_ref,
13713                                             good_mir,ngood_mir,ngood_mir_ref,
13714                                             degree,numbering,&xnbtot,&xnbop))
13715 		    {
13716 		        all_5_bangles(newbang,&newnbang);
13717                         scanmin5(xnbtot,xnbop,nv==splitlevel||nv==splitlevel+1,
13718                                  newprevA,0,newbang,newnbang);
13719 		    }
13720 	        }
13721 	    }
13722 	}
13723         reduce_min5_b(extBred,extBmirror[i]);
13724     }
13725 
13726     for (i = 0; i < nextC; ++i)
13727     {
13728         extCred = extend_min5_c(extC[i],&extCanchor);
13729 #ifdef FAST_FILTER_MIN5
13730         if (FAST_FILTER_MIN5)
13731 #endif
13732         {
13733             if (!has_min5_a() && !has_min5_b())
13734             {
13735 	        for (j = 0; j < nv-1; ++j)
13736 		    if (is_min5_c_centre(j)) colour[j] = 2;
13737 		    else                     colour[j] = degree[j];
13738 	        colour[nv-1] = 2;
13739 
13740                 if (canon(colour,numbering,&xnbtot,&xnbop))
13741 	        {
13742 		    all_5_bangles(newbang,&newnbang);
13743                     scanmin5(xnbtot,xnbop,nv>=splitlevel&&nv<=splitlevel+4,
13744 			     newprevA,0,newbang,newnbang);
13745 	        }
13746             }
13747         }
13748         reduce_min5_c(extCred,extCanchor);
13749     }
13750 
13751     if (dosplit)
13752         for (i = 0; i < nv; ++i) firstedge[i] = firstedge_save[i];
13753 }
13754 
13755 /****************************************************************************/
13756 
13757 static void
make_cube(void)13758 make_cube(void)
13759 
13760 /* Make a cube using the first 24 edges */
13761 {
13762    int i;
13763    EDGE *buffer;
13764 
13765     for (i=0; i<8; i++)
13766       { buffer=edges+3*i;
13767         firstedge[i]=buffer; degree[i]=3;
13768         buffer->next=buffer+1; buffer->prev=buffer+2; buffer->start=i;
13769         buffer++; buffer->next=buffer+1; buffer->prev=buffer-1; buffer->start=i;
13770         buffer++; buffer->next=buffer-2; buffer->prev=buffer-1; buffer->start=i;
13771       }
13772 
13773     buffer=edges; /* edge number 0 */
13774     buffer->end=4;
13775     buffer->invers=edges+12;
13776     buffer->min=buffer;
13777 
13778     buffer++; /* edge number 1 */
13779     buffer->end=3;
13780     buffer->invers=edges+11;
13781     buffer->min=buffer;
13782 
13783     buffer++; /* edge number 2 */
13784     buffer->end=1;
13785     buffer->invers=edges+4;
13786     buffer->min=buffer;
13787 
13788     buffer++; /* edge number 3 */
13789     buffer->end=5;
13790     buffer->invers=edges+15;
13791     buffer->min=buffer;
13792 
13793     buffer++; /* edge number 4 */
13794     buffer->end=0;
13795     buffer->invers=edges+2;
13796     buffer->min=buffer->invers;
13797 
13798     buffer++; /* edge number 5 */
13799     buffer->end=2;
13800     buffer->invers=edges+7;
13801     buffer->min=buffer;
13802 
13803     buffer++; /* edge number 6 */
13804     buffer->end=6;
13805     buffer->invers=edges+18;
13806     buffer->min=buffer;
13807 
13808     buffer++; /* edge number 7 */
13809     buffer->end=1;
13810     buffer->invers=edges+5;
13811     buffer->min=buffer->invers;
13812 
13813     buffer++; /* edge number 8 */
13814     buffer->end=3;
13815     buffer->invers=edges+10;
13816     buffer->min=buffer;
13817 
13818     buffer++; /* edge number 9 */
13819     buffer->end=7;
13820     buffer->invers=edges+21;
13821     buffer->min=buffer;
13822 
13823     buffer++; /* edge number 10 */
13824     buffer->end=2;
13825     buffer->invers=edges+8;
13826     buffer->min=buffer->invers;
13827 
13828     buffer++; /* edge number 11 */
13829     buffer->end=0;
13830     buffer->invers=edges+1;
13831     buffer->min=buffer->invers;
13832 
13833     buffer++; /* edge number 12 */
13834     buffer->end=0;
13835     buffer->invers=edges;
13836     buffer->min=buffer->invers;
13837 
13838     buffer++; /* edge number 13 */
13839     buffer->end=5;
13840     buffer->invers=edges+17;
13841     buffer->min=buffer;
13842 
13843     buffer++; /* edge number 14 */
13844     buffer->end=7;
13845     buffer->invers=edges+22;
13846     buffer->min=buffer;
13847 
13848     buffer++; /* edge number 15 */
13849     buffer->end=1;
13850     buffer->invers=edges+3;
13851     buffer->min=buffer->invers;
13852 
13853     buffer++; /* edge number 16 */
13854     buffer->end=6;
13855     buffer->invers=edges+20;
13856     buffer->min=buffer;
13857 
13858     buffer++; /* edge number 17 */
13859     buffer->end=4;
13860     buffer->invers=edges+13;
13861     buffer->min=buffer->invers;
13862 
13863     buffer++; /* edge number 18 */
13864     buffer->end=2;
13865     buffer->invers=edges+6;
13866     buffer->min=buffer->invers;
13867 
13868     buffer++; /* edge number 19  */
13869     buffer->end=7;
13870     buffer->invers=edges+23;
13871     buffer->min=buffer;
13872 
13873     buffer++; /* edge number 20 */
13874     buffer->end=5;
13875     buffer->invers=edges+16;
13876     buffer->min=buffer->invers;
13877 
13878     buffer++; /* edge number 21 */
13879     buffer->end=3;
13880     buffer->invers=edges+9;
13881     buffer->min=buffer->invers;
13882 
13883     buffer++; /* edge number 22 */
13884     buffer->end=4;
13885     buffer->invers=edges+14;
13886     buffer->min=buffer->invers;
13887 
13888     buffer++; /* edge number 23 */
13889     buffer->end=6;
13890     buffer->invers=edges+19;
13891     buffer->min=buffer->invers;
13892 
13893     nv=8;
13894     ne=24;
13895 }
13896 
13897 /************************************************************************/
13898 
13899 static int
threeconn_quad(EDGE * e)13900 threeconn_quad(EDGE *e)
13901 
13902 /* Difference to "threeconn": On the left hand side of e there must be a
13903    quadrangle instead of a triangle.
13904 
13905    tests whether the graph obtained by deleting EDGE e is still 3-connected.
13906    The edge e may have been deleted or not, but the values in e must be
13907    as before it was (possibly) deleted. The map must have been 3-connected
13908    before -- so especially there weren't any vertices of degree 2.
13909    degree[] is not assumed correct for the endvertices of e.
13910 
13911    On the left hand side of e there must be a quadrangle.
13912    (e->left_facesize==4) and it is assumed that it is checked before
13913    that the endvertices adjacent to e have degree at least 3 after the
13914    deletion.
13915 
13916    The way it works: If there is a 2-cut, e->start and e->end cannot
13917    be contained, but they must be in different components after
13918    removing e, so both faces neighbouring e must contain a
13919    cutvertex. Because on the left hand side there is a quadrangle this
13920    means that v=e->prev->end or w=e->invers->next->end MUST be
13921    contained.  It is checked whether v or w is contained in a face that
13922    shares yet another vertex with the face formerly on the right hand
13923    side of e (the new face obtained by deleting e).
13924 
13925    Note that this face cannot be the one v shares with e->start or
13926    w shares with e->end because that would have meant that a 2-cut
13927    already existed in the graph.
13928 
13929    Returns 1 if it is 3-connected after deleting e, 0 else.  */
13930 
13931 {
13932     EDGE *run, *start, *end;
13933 
13934     RESETMARKS_V;
13935 
13936     /* The endvertices of e need not be marked */
13937     for ( run=e->next, end=e->invers->prev->invers ;
13938           run != end; run=run->invers->next) MARK_V(run->end);
13939 
13940 
13941     /* OK -- now test v. */
13942 
13943     start=e->prev->invers;
13944 
13945     end=start->prev;
13946 
13947     /* the face on the right hand side of start contains e->start so
13948        need not be tested: */
13949 
13950     start=start->next;
13951 
13952     while (start != end)
13953       { run=start->invers;
13954         start=start->next;
13955         for ( ; run != start; run=run->prev->invers)
13956 	    if (ISMARKED_V(run->start)) return 0;
13957       }
13958 
13959     /* OK -- now test w. The face that also contains v was already tested */
13960 
13961     if (degree[end->end]==3) return 1;
13962 
13963     start=end->invers->next;
13964     end=end->invers->prev->prev;
13965 
13966     while (start != end)
13967       { run=start->invers;
13968         start=start->next;
13969         for ( ; run != start; run=run->prev->invers)
13970 	    if (ISMARKED_V(run->start)) return 0;
13971       }
13972 
13973     return 1;
13974 }
13975 
13976 /************************************************************************/
13977 
13978 static int
twoconn_quad(EDGE * e)13979 twoconn_quad(EDGE *e)
13980 
13981 /* tests whether the graph obtained by deleting EDGE e is still 2-connected.
13982    The edge e may have been deleted or not, but the values in e must be
13983    as before it was (possibly) deleted. The map must have been 2-connected
13984    before.  degree[] is not assumed correct for the endvertices of e.
13985 
13986    On the left hand side of e there must be a quadrangle (e->left_facesize==3).
13987 
13988    If there is a 1-cut, it cannot be e->start or e->end (otherwise
13989    it was a 1-cut before), but they must be in different components, (same
13990    reason), so v=e->prev->end or w=e->invers->next->end MUST be the cutvertex.
13991    It is checked whether v or w are contained in the face on the right hand side
13992    of e (before deleting).
13993 
13994    Returns 1 if it is 2-connected after deleting e, 0 else.
13995 */
13996 
13997 {
13998     EDGE *run, *end;
13999 
14000     RESETMARKS_V;
14001 
14002     MARK_V(e->prev->end);
14003     MARK_V(e->invers->next->end);
14004 
14005     end = e->next->invers;
14006 
14007     for (run = e->invers->prev; run != end; run = run->invers->prev)
14008         if (ISMARKED_V(run->end)) return 0;
14009 
14010    return 1;
14011 }
14012 
14013 
14014 /***************************************************************/
14015 
14016 #if 0
14017 static int
14018 edge_del_conn_quad(EDGE *e, int connectivity)
14019 
14020 /* computes the connectivity of the graph after the removal of edge e.
14021 
14022    The edge e may have been deleted or not, but the values in e must be
14023    as before it was (possibly) deleted.  degree[] is not assumed correct
14024    for the endvertices of e.
14025    The variable connectivity gives the largest possible value k in {1,2,3}
14026    so that the map is k-connected before the removal of e. Larger values
14027    for the connectivity lead to an error. The value returned is also one
14028    of 1,2,3.
14029 
14030    On the left hand side of e there must be a quadrangle (e->left_facesize==4).
14031 */
14032 
14033 {
14034   if (connectivity==3) return (2+threeconn_quad(e));
14035   if (connectivity==2) return (1+twoconn_quad(e));
14036   return 1;
14037 }
14038 #endif
14039 
14040 /************************************************************************/
14041 
14042 static void
prune_bip_edgelist(EDGE * old[],int numold,EDGE * newe[],int * numnew)14043 prune_bip_edgelist(EDGE *old[], int numold, EDGE *newe[], int *numnew)
14044 
14045 /* Copy from old[0..numold-1] to newe[0..*numnew-1] each edge e with
14046  *    these two properties:
14047  *       1. Both ends of e have degree >= minpolydeg+1.
14048  *          2. e is contained in a 4-face.
14049  *            It is legal that old and newe and &numold and numnew are the same.
14050  */
14051 
14052 {
14053     int i,counter=0;
14054     EDGE *e;
14055 
14056     for (i=0; i<numold; i++, old++)
14057       { e = *old;
14058         if (degree[e->start] > minpolydeg && degree[e->end] > minpolydeg
14059              && (e->left_facesize == 4 || e->invers->left_facesize == 4))
14060             newe[counter++]=e;
14061       }
14062 
14063     *numnew=counter;
14064 }
14065 
14066 /*************************************************************************/
14067 
14068 static int
maybe_delete_bip(EDGE * edel,int oldmaxface,int oldmaxlist0,int oldmaxlist1,int * newmaxface,int * newmaxlist0,int * newmaxlist1,EDGE * good_or[],int * ngood_or,int * ncan_or,EDGE * good_inv[],int * ngood_inv,int * ncan_inv,int * connec)14069 maybe_delete_bip(EDGE *edel, int oldmaxface, int oldmaxlist0, int oldmaxlist1,
14070              int *newmaxface, int *newmaxlist0, int *newmaxlist1,
14071              EDGE *good_or[], int *ngood_or, int *ncan_or,
14072              EDGE *good_inv[], int *ngood_inv, int *ncan_inv, int *connec)
14073 
14074 /* Assumes there is a 4-face on the left of *edel, and that *edel can be
14075    deleted while keeping degrees >= minpolydeg.  Also, the new face created
14076    will be a largest face.  oldmaxface is the size of the largest face so far,
14077    and inmaxface[oldmaxlist0..oldmaxlist1-1] are the edges with a face of
14078    maximum size on the left.  *connec is the current connectivity.
14079 
14080    This procedure deletes *edel provided the result is at least as connected
14081    as minpolyconnec, and that the procedure believes the re-insertion of *edel
14082    might be a canonical edge insertion.  The latter decision is based on
14083    four combinatorial invariates: the three vertex degrees at the ends of
14084    *edel and on its left, and the size of the face to the left of edel->prev.
14085 
14086    In case *edel passes the test and is deleted, the edges which may
14087    represent the re-insertion of *edel and optimise the four-part invariant
14088    mentioned above are put in good_or[0..*ncan_or-1] and
14089    good_inv[0..*ncan_inv-1].  This will include at least one of the edges
14090    edel->prev, edel->invers->next and (if there is also a 4-face on the
14091    right of *edel) edel->next and edel->invers->prev.  Then all other edges
14092    which might possibly represent canonical edge insertions are put in
14093    good_or[*ncan_or..*ngood_or-1] or good_inv[*ncan_inv..*ngood_inv-1].
14094    The *_or edges are those for which the inserted edge will be in the
14095    next direction, and the *_inv edges .. the prev direction.
14096 
14097    In addition, if *edel is deleted, inmaxface[*newmaxlist0..*newmaxlist1-1]
14098    will have all edges with a maximum face on the left (that size being put
14099    into *newmaxface).  This list may overlap
14100    inmaxface[oldmaxlist0..oldmaxlist1-1] if the max face size does not
14101    increase.
14102 
14103    In the case of value 0, *connec is changed to represent the new
14104    connectivity.
14105    Return values:   0 = ok
14106                     1 = rejected as connectivity will be too small
14107                     2 = rejected by colour
14108 */
14109 {
14110 
14111 #define DEGENDB(e) (degree[e->end])
14112 #define OROKB(e) ISNEQADJ(e->start,e->invers->prev->invers->prev->end)
14113 #define INVOKB(e) ISNEQADJ(e->start,e->invers->next->invers->next->end)
14114 #define REJECTB(x) {++degree[v1]; ++degree[v2]; return x;}
14115 #define ORTESTB(e) {col = DEGENDB(e); if (col > maxcol) \
14116   {if (OROKB(e)) REJECTB(2)} \
14117    else if (col==maxcol&&OROKB(e)) good_or[ng_or++]=e;}
14118 #define INVTESTB(e) {col = DEGENDB(e); if (col > maxcol) \
14119   {if (INVOKB(e)) REJECTB(2)} \
14120    else if (col==maxcol&&INVOKB(e)) good_inv[ng_inv++]=e;}
14121 #define ORCOLB(e) (((long)degree[e->invers->prev->end] << 10)  \
14122                       + e->left_facesize)
14123 #define INVCOLB(e) \
14124  (((long)degree[e->invers->next->end] << 10) + e->invers->left_facesize)
14125 
14126     EDGE *e1,*e2,*e3,*e4,*e5,*e6,*ee,*ea,*eb;
14127     long col,maxcol;
14128     int k,i,ng_or,ng_inv,nc_or,nc_inv;
14129     int maxface,v1,v2,v3,v4,v5,v6;
14130     int da,db,mindeg,maxdeg,nml1;
14131     int newconnec;
14132 
14133     maxface = *newmaxface = edel->invers->left_facesize + 2;
14134     if (maxface > oldmaxface) oldmaxlist0 = oldmaxlist1;
14135     *newmaxlist0 = oldmaxlist0;
14136 
14137     *ngood_or = *ngood_inv = 0;
14138 
14139  /* Now old edges that will be on a largest face (if *edel is deleted)
14140     are in places oldmaxlist0..oldmaxlist1-1.  New edges will be from
14141     oldmaxlist1 to *newmaxlist1-1, but *newmaxlist1 is not set yet. */
14142 
14143     v1 = edel->start;  v2 = edel->end;
14144 
14145     /* maxdeg = (degree[v1] > degree[v2] ? degree[v1] : degree[v2]) - 1; */
14146     if (degree[v1] < degree[v2])
14147     {
14148 	mindeg = degree[v1]-1; maxdeg = degree[v2]-1;
14149     }
14150     else
14151     {
14152 	mindeg = degree[v2]-1; maxdeg = degree[v1]-1;
14153     }
14154 
14155     e1 = edel->prev; v3 = e1->end;
14156     e4 = edel->next; v4 = e4->end;
14157     e3 = edel->invers->prev; v6 = e3->end;
14158     e2 = edel->invers->next; v5 = e2->end;
14159 
14160    /* The following is an efficiency short-cut, but it is assumed
14161       to have been done below. */
14162 
14163     if (ISNEQADJ(v3,v6) && (degree[v3] > maxdeg || degree[v6] > maxdeg))
14164 	return 2;
14165     if (ISNEQADJ(v4,v5) && (degree[v4] > maxdeg || degree[v5] > maxdeg))
14166 	return 2;
14167 
14168     --degree[v1];
14169     --degree[v2];
14170 
14171     maxcol = nc_or = nc_inv = 0;
14172 
14173     if (degree[v1] == maxdeg)
14174     {
14175         col = DEGENDB(e1);
14176 	maxcol = col;
14177         good_or[nc_or++] = e1;
14178 
14179         if (maxface == 6)
14180 	{
14181 	    col = DEGENDB(e4);
14182 	    if (col > maxcol)
14183 	    {
14184 		nc_or = nc_inv = 0;
14185 		good_inv[nc_inv++] = e4;
14186 		maxcol = col;
14187 	    }
14188 	    else if (col == maxcol)
14189 	        good_inv[nc_inv++] = e4;
14190 	}
14191     }
14192 
14193     if (degree[v2] == maxdeg)
14194     {
14195 	col = DEGENDB(e2);
14196 	if (col > maxcol)
14197   	{
14198 	    nc_or = nc_inv = 0;
14199             good_inv[nc_inv++] = e2;
14200 	    maxcol = col;
14201 	}
14202 	else if (col == maxcol)
14203 	    good_inv[nc_inv++] = e2;
14204 
14205 	if (maxface == 6)
14206 	{
14207             col = DEGENDB(e3);
14208 	    if (col > maxcol)
14209 	    {
14210 		nc_or = nc_inv = 0;
14211 		good_or[nc_or++] = e3;
14212 		maxcol = col;
14213 	    }
14214 	    else if (col == maxcol)
14215 		good_or[nc_or++] = e3;
14216 	}
14217     }
14218 
14219     ng_or = nc_or;  ng_inv = nc_inv;
14220 
14221     if (maxface == 6)
14222     {
14223      /* Recall from above that all degrees are <= maxdeg whenever
14224         edges are possible. */
14225 
14226 	e5 = e1->invers->prev;
14227 	e6 = e3->invers->prev;
14228 
14229 	if (ISNEQADJ(v3,v6))
14230 	{
14231 	    if (degree[v3] == maxdeg)
14232 	    {
14233 		if (degree[v1] > maxcol) REJECTB(2)
14234 	        else if (degree[v1] == maxcol) good_inv[ng_inv++] = e1->invers;
14235 		if (degree[v5] > maxcol) REJECTB(2)
14236 		else if (degree[v5] == maxcol) good_or[ng_or++] = e5;
14237 	    }
14238 
14239 	    if (degree[v6] == maxdeg)
14240 	    {
14241 		if (degree[v4] > maxcol) REJECTB(2)
14242 	        else if (degree[v4] == maxcol) good_or[ng_or++] = e6;
14243 		if (degree[v2] > maxcol) REJECTB(2)
14244 		else if (degree[v2] == maxcol) good_inv[ng_inv++] = e3->invers;
14245 	    }
14246 	}
14247 
14248 	if (ISNEQADJ(v4,v5))
14249 	{
14250 	    if (degree[v4] == maxdeg)
14251 	    {
14252 		if (degree[v6] > maxcol) REJECTB(2)
14253 	        else if (degree[v6] == maxcol) good_inv[ng_inv++] = e6->invers;
14254 		if (degree[v1] > maxcol) REJECTB(2)
14255 		else if (degree[v1] == maxcol) good_or[ng_or++] = e4->invers;
14256 	    }
14257 
14258 	    if (degree[v5] == maxdeg)
14259 	    {
14260 		if (degree[v2] > maxcol) REJECTB(2)
14261 	        else if (degree[v2] == maxcol) good_or[ng_or++] = e2->invers;
14262 		if (degree[v3] > maxcol) REJECTB(2)
14263 		else if (degree[v3] == maxcol) good_inv[ng_inv++] = e5->invers;
14264 	    }
14265 	}
14266 
14267         nml1 = oldmaxlist1;
14268         inmaxface[nml1++] = e1->invers;
14269         inmaxface[nml1++] = e2;
14270         inmaxface[nml1++] = e3->invers;
14271         inmaxface[nml1++] = e4;
14272         inmaxface[nml1++] = e5->invers;
14273         inmaxface[nml1++] = e6->invers;
14274     }
14275     else
14276     {
14277 	/* Recall from above that degree[v3,v6] <= maxdeg if v3 notadj v6
14278                               and degree[v4,v5] <= maxdeg if v4 notadj v5 */
14279 
14280 	e5 = e1->invers->prev;
14281 
14282 	if (ISNEQADJ(v3,v6))
14283 	{
14284 	    if (degree[v3] == maxdeg)
14285 	    {
14286 		if (degree[v5] > maxcol) REJECTB(2)
14287                 else if (degree[v5] == maxcol) good_or[ng_or++] = e5;
14288 	    }
14289 	    if (degree[v6] == maxdeg)
14290 	    {
14291 		if (degree[v2] > maxcol) REJECTB(2)
14292                 else if (degree[v2] == maxcol) good_inv[ng_inv++] = e3->invers;
14293             }
14294 	}
14295 	if (ISNEQADJ(v4,v5))
14296 	{
14297 	    if (degree[v5] == maxdeg)
14298             {
14299                 if (degree[v3] > maxcol) REJECTB(2)
14300                 else if (degree[v3] == maxcol) good_inv[ng_inv++] = e5->invers;
14301             }
14302             if (degree[v4] == maxdeg)
14303             {
14304                 if (degree[v1] > maxcol) REJECTB(2)
14305                 else if (degree[v1] == maxcol) good_or[ng_or++] = e4->invers;
14306             }
14307 	}
14308 
14309         nml1 = oldmaxlist1;
14310 
14311         ea = e2;
14312 	eb = e3->invers->prev;
14313 	do
14314 	{
14315 	    if (ISNEQADJ(ea->end,eb->end))
14316 	    {
14317 		da = DEGENDB(ea);
14318 		db = DEGENDB(eb);
14319 		if (da > maxdeg || db > maxdeg) REJECTB(2);
14320 
14321 		if (da == maxdeg)
14322 		{
14323 		    if (degree[ea->start] > maxcol) REJECTB(2)
14324 		    else if (degree[ea->start] == maxcol)
14325                         good_or[ng_or++] = ea->invers;
14326 		}
14327 		if (db == maxdeg)
14328 		{
14329 		    if (degree[eb->start] > maxcol) REJECTB(2)
14330 		    else if (degree[eb->start] == maxcol)
14331                         good_inv[ng_inv++] = eb->invers;
14332 		}
14333 	    }
14334 	    inmaxface[nml1++] = ea;
14335 	    ea = eb->next;
14336 	    eb = eb->invers->prev;
14337 	    if (eb == edel) eb = e1;
14338 	} while (eb != e5);
14339 
14340         inmaxface[nml1++] = e5->invers;
14341         inmaxface[nml1++] = e1->invers;
14342         inmaxface[nml1++] = e4;
14343     }
14344 
14345  /* Now test old edges still on max faces */
14346 
14347     for (i = oldmaxlist0; i < oldmaxlist1; ++i)
14348     {
14349 	ee = inmaxface[i];
14350 	if (degree[ee->start] > maxdeg)
14351 	{
14352 	    if (INVOKB(ee)) REJECTB(2);
14353             ee = ee->prev;
14354             if (OROKB(ee)) REJECTB(2);
14355 	}
14356 	else if (degree[ee->start] == maxdeg)
14357 	{
14358 	    INVTESTB(ee);
14359 	    ee = ee->prev;
14360 	    ORTESTB(ee);
14361 	}
14362     }
14363 
14364     if (mindeg < *connec)
14365 	newconnec = mindeg;
14366     else if (*connec == 3)
14367 	newconnec = 2 + threeconn_quad(edel);
14368     else if (*connec == 2)
14369 	newconnec = 1 + twoconn_quad(edel);
14370     else
14371 	newconnec = 1;
14372 
14373     if (newconnec < minpolyconnec) REJECTB(1);
14374 
14375  /* Now we have complete success!  Just prune the lists a bit and
14376     complete the deletion of edel. */
14377 
14378     edel->prev->next = edel->next;
14379     edel->next->prev = edel->prev;
14380     ee = edel->invers;
14381     ee->prev->next = ee->next;
14382     ee->next->prev = ee->prev;
14383 
14384     for (i = oldmaxlist1; i < nml1; ++i)
14385 	inmaxface[i]->left_facesize = maxface;
14386 
14387     firstedge[v1] = e1;
14388     firstedge[v2] = e2;
14389     ne -= 2;
14390 
14391     *connec = newconnec;
14392 
14393     *newmaxlist1 = nml1;
14394     *ngood_or = ng_or;
14395     *ngood_inv = ng_inv;
14396     *ncan_or = nc_or;
14397     *ncan_inv = nc_inv;
14398 
14399     if (ng_or + ng_inv == 1) return 0;
14400 
14401     maxcol = 0;
14402     for (i = 0; i < nc_or; ++i)
14403         if (ORCOLB(good_or[i]) > maxcol) maxcol = ORCOLB(good_or[i]);
14404     for (i = 0; i < nc_inv; ++i)
14405         if (INVCOLB(good_inv[i]) > maxcol) maxcol = INVCOLB(good_inv[i]);
14406 
14407     for (i = 0, k = 0; i < nc_or; ++i)
14408         if (ORCOLB(good_or[i]) == maxcol) good_or[k++] = good_or[i];
14409     *ncan_or = k;
14410     for (; i < ng_or; ++i)
14411     {
14412 	col = ORCOLB(good_or[i]);
14413         if (col == maxcol)
14414 	    good_or[k++] = good_or[i];
14415         else if (col > maxcol)
14416         {
14417             insert_edge_general(edel);
14418             *ngood_or = *ngood_inv = 0;
14419 	    return 2;
14420         }
14421     }
14422     *ngood_or = ng_or = k;
14423 
14424     for (i = 0, k = 0; i < nc_inv; ++i)
14425         if (INVCOLB(good_inv[i]) == maxcol) good_inv[k++] = good_inv[i];
14426     *ncan_inv = k;
14427     for (; i < ng_inv; ++i)
14428     {
14429 	col = INVCOLB(good_inv[i]);
14430         if (col == maxcol)
14431             good_inv[k++] = good_inv[i];
14432         else if (col > maxcol)
14433         {
14434             insert_edge_general(edel);
14435             *ngood_or = *ngood_inv = 0;
14436 	    return 2;
14437         }
14438     }
14439     *ngood_inv = ng_inv = k;
14440 
14441     return 0;
14442 }
14443 
14444 /*************************************************************************/
14445 
14446 static void
scanbip(int nbtot,int nbop,EDGE * oldfeas[],int noldfeas,int oldmaxface,int oldmaxlist0,int oldmaxlist1,int connec)14447 scanbip(int nbtot, int nbop, EDGE *oldfeas[], int noldfeas,
14448         int oldmaxface, int oldmaxlist0, int oldmaxlist1, int connec)
14449 
14450 /* This is the recursive search procedure for bipartite graphs.
14451  * oldfeas[0..noldfeas-1] are the edges which can be removed without
14452  * violating the degree bound minpolydeg, with some (but not necessarily
14453  * all) missing because they are known to violate the connectivity
14454  * bound minpolyconnec.  nbtot/nbop represent the group, as usual.
14455  * oldmaxface is the size of the largest face.
14456  * inmaxface[oldmaxlist0..oldmaxlist1-1] lists the edges whose
14457  * left face has greatest size (unless that is 4).  connec is
14458  * the actual connectivity. */
14459 {
14460     EDGE *newfeas[MAXE/2],*good_or[MAXE],*good_inv[MAXE],*e,*esave;
14461     int i,nnewfeas,minimal[MAXE/2],newmaxface;
14462     int code,xnbtot,xnbop;
14463     int ngood_or,ncan_or,ngood_inv,ncan_inv;
14464     int newmaxlist0,newmaxlist1,newconnec;
14465 
14466     if (ne <= edgebound[1]) got_one(nbtot,nbop,connec);
14467     if (ne == edgebound[0]) return;
14468     if (ne - 2*noldfeas > edgebound[1]) return;
14469 
14470 #ifdef PRE_FILTER_BIPPOLY
14471     if (!(PRE_FILTER_BIPPOLY)) return;
14472 #endif
14473 
14474     mark_edge_orbits(oldfeas,noldfeas,minimal,nbtot);
14475 
14476     for (i = 0; i < noldfeas; ++i)
14477     {
14478         if (!minimal[i]) continue;
14479 
14480         e = oldfeas[i];
14481         if (e->left_facesize != 4) e = e->invers;
14482         if (e->invers->left_facesize < oldmaxface-2
14483                       || e->invers->left_facesize == maxfacesize)
14484             continue;
14485 
14486         AMDELEDGE(e->start,e->end);
14487 
14488         newconnec = connec;
14489         code = maybe_delete_bip(e,oldmaxface,oldmaxlist0,oldmaxlist1,
14490                             &newmaxface,&newmaxlist0,&newmaxlist1,
14491                             good_or,&ngood_or,&ncan_or,
14492                             good_inv,&ngood_inv,&ncan_inv,&newconnec);
14493 
14494         if (code == 0)
14495         {
14496 #ifdef FAST_FILTER_BIPPOLY
14497             if (FAST_FILTER_BIPPOLY)
14498 #endif
14499             {
14500                 if (ngood_or + ngood_inv == 1)
14501                 {
14502                     esave = oldfeas[i];
14503                     oldfeas[i] = oldfeas[noldfeas-1];
14504                     prune_bip_edgelist(oldfeas,noldfeas-1,newfeas,&nnewfeas);
14505                     oldfeas[i] = esave;
14506                     scanbip(1,1,newfeas,nnewfeas,
14507                              newmaxface,newmaxlist0,newmaxlist1,newconnec);
14508                 }
14509                 else if (canon_edge_oriented(good_or,ngood_or,ncan_or,
14510                                              good_inv,ngood_inv,ncan_inv,
14511                                              degree,numbering,&xnbtot,&xnbop))
14512                 {
14513                  /* The following line corrects for the fact that canon*()
14514                     finds each automorphism twice if the maximum degree is
14515                     at most 2.  However, it interferes with -o so is disabled.
14516 		    CHECK THIS
14517 
14518                     if (ne <= 2*nv && maxdegree() <= 2) xnbtot = xnbop; */
14519 
14520                     esave = oldfeas[i];
14521                     oldfeas[i] = oldfeas[noldfeas-1];
14522                     prune_bip_edgelist(oldfeas,noldfeas-1,newfeas,&nnewfeas);
14523                     oldfeas[i] = esave;
14524                     scanbip(xnbtot,xnbop,newfeas,nnewfeas,
14525                              newmaxface,newmaxlist0,newmaxlist1,newconnec);
14526                 }
14527             }
14528             insert_edge_general(e);
14529         }
14530 	else if (code == 1)
14531         {
14532             oldfeas[i] = oldfeas[noldfeas-1];
14533             minimal[i] = minimal[noldfeas-1];
14534             --i;
14535             --noldfeas;
14536         }
14537         AMADDEDGE(e->start,e->end);
14538     }
14539 }
14540 
14541 /*************************************************************************/
14542 
14543 static int
con_quad(void)14544 con_quad(void)
14545 
14546 /* tests and returns the connectivity of a simple quadrangulation.
14547    Possible values are 2 and 3 */
14548 {
14549 
14550   int i,othervertex;
14551   EDGE *start, *run, *end, *runend, *buffer;
14552   static EDGE *lastprob=NULL;
14553   static int lastdeg= -1;
14554   /* the last two remember edges or vertices where the last time there
14555      was a problem -- test these first */
14556 
14557   if (lastdeg>=0) { if (degree[lastdeg]==2)  return 2;}
14558 
14559   RESETMARKS;
14560 
14561   if ((lastprob != NULL) && (degree[lastprob->start]>3))
14562     { MARK(lastprob);
14563       buffer=lastprob->invers->prev;
14564       othervertex=buffer->end;
14565       if (degree[othervertex]>3)
14566 	{
14567 	  MARK(buffer->invers->prev);
14568 	  runend=lastprob->prev;
14569 	  run=lastprob->next->next;
14570 	  while (run!=runend)
14571 	    { if (run->invers->prev->end==othervertex) return 2;
14572 	    run=run->next; }
14573 	}
14574     }
14575 
14576   lastdeg= -1;
14577   lastprob=NULL;
14578 
14579   for (i=0;i<nv;i++) if (degree[i]==2) { lastdeg=i; return 2;}
14580 
14581   /* Note: edges on the other side of degree 3 vertices in a
14582      quadrangle can be marked as non-starts. but this makes it
14583      much slower (doing it in the loop or doing it before.
14584      Don't ask why... */
14585 
14586   for (i=0;i<nv-1;i++) /* the faces around nv are all tested from
14587 			  the other side */
14588    { if (degree[i]>3)
14589       { start=end=firstedge[i]; /* checking face on the right */
14590       do
14591 	{
14592 	  if (!ISMARKED(start))
14593 	    { MARK(start);
14594 	      buffer=start->invers->prev;
14595 	      othervertex=buffer->end;
14596 	      if (degree[othervertex]>3)
14597 		{
14598 		  MARK(buffer->invers->prev);
14599 		  runend=start->prev;
14600 		  run=start->next->next;
14601 		  while (run!=runend)
14602 		    { if (run->invers->prev->end==othervertex)
14603 		      { lastprob=start; return 2; }
14604 		      run=run->next; }
14605 		}
14606 	      /* Makes it slower... -- also outside the edge-loop
14607 	      if (degree[i]==4)
14608 		{ MARK(start->next->next);
14609 		MARK(start->prev->invers->next->invers);
14610 		}
14611 	      */
14612 	    }
14613 	  start=start->next;
14614 	} while (start!=end);
14615       }
14616    }
14617 
14618   return 3;
14619 
14620 }
14621 
14622 /**************************************************************************/
14623 
14624 static void
startbipscan(int nbtot,int nbop,int conn)14625 startbipscan(int nbtot, int nbop, int conn)
14626 
14627 /* This routine begins the scan for general connected bipartite planar graphs
14628  * formed by removing edges from quadrangulations.  The current graph is
14629  * a quadrangulation, and the group is known (parameters nbtot,nbop).
14630  * conn is the connectivity (2 or 3, must be correct).
14631  */
14632 
14633 {
14634     EDGE *feasible[MAXE/2];
14635     EDGE *e,*ex;
14636     int i,j,nfeas;
14637 
14638     for (i = 0; i < nv; ++i)
14639     {
14640 	for (j = 0; j < nv; ++j) am2[i][j] = 0;
14641 	am2[i][i] = 1;
14642     }
14643 
14644     nfeas = 0;
14645     for (i = 0; i < nv; ++i)
14646     {
14647         e = ex = firstedge[i];
14648         do
14649         {
14650             if (e == e->min && degree[e->start] > minpolydeg
14651                             && degree[e->end] > minpolydeg)
14652                 feasible[nfeas++] = e;
14653             e->left_facesize = 4;
14654             am2[e->start][e->end] = 1;
14655             e = e->next;
14656         } while (e != ex);
14657     }
14658 
14659     prune_bip_edgelist(feasible,nfeas,feasible,&nfeas);
14660 
14661     scanbip(nbtot,nbop,feasible,nfeas,4,0,0,conn);
14662 }
14663 
14664 /**************************************************************************/
14665 
14666 static void
make_me_a_star(int n)14667 make_me_a_star(int n)
14668 
14669 /* Makes a star on n vertices -- so one vertex of degree n-1
14670    and n-1 vertices of degree 1 */
14671 {
14672    int i;
14673    EDGE *buffer, *buffer2;
14674 
14675    if (n==1) { nv=1; ne=0; firstedge[0]=NULL; return; }
14676 
14677    firstedge[0]=edges;
14678    degree[0]=n-1;
14679    for (i=1, buffer=edges, buffer2=edges+n-1;
14680 	i<=n-1;i++,buffer++,buffer2++)
14681      { buffer->start=buffer2->end=0;
14682        buffer->end=buffer2->start=i;
14683        buffer->invers=buffer2;
14684        buffer2->invers=buffer;
14685        buffer->min=buffer2->min=buffer;
14686        buffer2->prev=buffer2->next=buffer2;
14687        degree[i]=1;
14688        firstedge[i]=buffer2;
14689      }
14690 
14691    buffer=edges; /* buffer leading to 1 */
14692    if (n>2) buffer->next=buffer+1; else buffer->next=buffer;
14693    buffer->prev=buffer+n-2;
14694    for (i=2,buffer++; i<n-1; i++, buffer++) /* buffer leading to i */
14695      { buffer->prev=buffer-1;
14696        buffer->next=buffer+1;
14697      }
14698    if (n>2) /* buffer leading to n-1 */
14699      {
14700        buffer->prev=buffer-1;
14701        buffer->next=edges;
14702      }
14703 
14704     nv=n;
14705     ne=2*(n-1);
14706 }
14707 
14708 /**************************************************************************/
14709 
14710 static void
make_cycle(int n)14711 make_cycle(int n)
14712 
14713 /* Makes a cycle on n vertices and uses the first 2n edges of the
14714    vector edges[] for it. Interpretation: a 1-cycle is a loop,
14715    a 2-cycle a double-edge. */
14716 
14717 {
14718    int i, end;
14719    EDGE *buffer, *bufferb;
14720 
14721    /* edges+2*i always leads from i to i+1 (mod n) and edges+2*i+1
14722       leads back. */
14723 
14724    for (i=0;i<=n-1;i++)
14725      { end=(i+1)%n;
14726      degree[i]=2;
14727      buffer=edges+(2*i);
14728      firstedge[i]=buffer;
14729      bufferb=buffer+1;
14730      buffer->invers=bufferb;
14731      bufferb->invers=buffer;
14732      buffer->min=bufferb->min=buffer;
14733      buffer->start=bufferb->end=i;
14734      bufferb->start=buffer->end=end;
14735      if (i>0) buffer->prev=buffer->next=buffer-1;
14736      else buffer->prev=buffer->next=edges+2*n-1;
14737      if (i<n-1) bufferb->prev=bufferb->next=bufferb+1;
14738      else bufferb->prev=bufferb->next=edges;
14739      }
14740 
14741    nv=n; ne=2*n;
14742 
14743    return;
14744 }
14745 
14746 /**************************************************************************/
14747 
14748 static void
make_gyro(void)14749 make_gyro(void)
14750 /* Make a loop with a vertex of degree 1 inside and outside. */
14751 {
14752 
14753   make_cycle(3);
14754   switch_edge(firstedge[0]);
14755 }
14756 
14757 /**************************************************************************/
14758 
14759 static void
initialize_min3_quadrangulations(void)14760 initialize_min3_quadrangulations(void)
14761 
14762 /* initialize edges for the 3-connected  and min3 quadrangulation
14763    generation, and make the inital cube */
14764 
14765 {
14766     EDGE *run,*start;
14767     int n,i;
14768 
14769 /* First initialize the edges for operation P1. They look like
14770 
14771        a
14772     \ / \ /
14773     ?b   c?   Vertex c is the new point. (a,c) and (d,c) are the
14774     / \ / \   new edges with a-->c taken as quadr_P1(n)
14775        d
14776 
14777 It is assumed that for 8<=n<MAXN after quadr_P1(n) there is room for 4 edges.
14778 */
14779 
14780     for (n=8; n<MAXN; n++)
14781       { run=start=quadr_P1(n);
14782         run->end=n; run->min=run;
14783         run->invers=start+1;
14784 
14785         run=start+1; run->start=n;
14786         run->min=run->invers=start; run->prev=start+3;
14787 
14788         run=start+2; run->end=n; run->min=run; run->invers=start+3;
14789 
14790         run=start+3; run->start=n; run->min=run->invers=start+2;
14791 	run->next=start+1;
14792       }
14793 
14794 
14795     /* The edges for operation P2 can't be "drawn" -- sorry
14796 
14797     It is assumed that after quadr_P2(n) there is room for 14 edges.
14798     */
14799 
14800     for (n=8; n<MAXN-2; n++)
14801       { start=quadr_P2(n);
14802 
14803         for (i=0;i<4;i++)
14804 	  { run=start+(2*i);
14805 	    run->invers=run+1;
14806 	    run->min=run;
14807 	    (run+1)->invers=(run+1)->min=run;
14808 	  }
14809 
14810 	run=start;
14811 	run->start=n; run->prev=start+7;
14812 
14813 	run=start+1; run->end=n;
14814 
14815 	run=start+2;
14816 	run->start=n+1; run->prev=start+4; run->next=start+6;
14817 
14818 	run=start+3; run->end=n+1;
14819 
14820 	run=start+4;
14821 	run->start=n+1; run->prev=start+6; run->next=start+2;
14822 
14823 	run=start+5; run->end=n+1;
14824 
14825 	run=start+6;
14826 	run->start=n+1; run->end=n; run->prev=start+2; run->next=start+4;
14827 
14828 	run=start+7;
14829 	run->start=n;  run->end=n+1;  run->next=start;
14830 
14831       }
14832 
14833     /* The edges for operation P3.
14834 
14835     It is assumed that after quadr_P3(n) there is room for 16 edges.
14836     */
14837 
14838     for (n=8; n<MAXN-4; n++)
14839       { start=quadr_P3(n);
14840 
14841       for (i=0; i<4; i++)
14842 	{ run=start+3*i;
14843 	  run->next=run+1; run->prev=run+2; run->start=n+i;
14844 	  run++; run->next=run+1; run->prev=run-1; run->start=n+i;
14845 	  run++; run->next=run-2; run->prev=run-1; run->start=n+i;
14846       }
14847 
14848       run=start; run->invers=start+12; run->min=run;
14849       run=start+1; run->invers=start+3; run->min=run; run->end=n+1;
14850       run=start+2; run->invers=start+11; run->min=run; run->end=n+3;
14851       run=start+3; run->invers=start+1; run->min=run->invers; run->end=n;
14852       run=start+4; run->invers=start+13; run->min=run;
14853       run=start+5; run->invers=start+6; run->min=run; run->end=n+2;
14854       run=start+6; run->invers=start+5; run->min=run->invers; run->end=n+1;
14855       run=start+7; run->invers=start+14; run->min=run;
14856       run=start+8; run->invers=start+9; run->min=run; run->end=n+3;
14857       run=start+9; run->invers=start+8; run->min=run->invers; run->end=n+2;
14858       run=start+10; run->invers=start+15; run->min=run;
14859       run=start+11; run->invers=start+2; run->min=run->invers; run->end=n;
14860       run=start+12; run->invers=start; run->min=run->invers; run->end=n;
14861       run=start+13; run->invers=start+4; run->min=run->invers; run->end=n+1;
14862       run=start+14; run->invers=start+7; run->min=run->invers; run->end=n+2;
14863       run=start+15; run->invers=start+10; run->min=run->invers; run->end=n+3;
14864 
14865       }
14866 
14867    make_cube();
14868 }
14869 
14870 /****************************************************************************/
14871 
14872 static void
make_P3(void)14873 make_P3(void)
14874 
14875 /* Make the path P3 */
14876 {
14877     EDGE *buffer;
14878 
14879     buffer=edges; /* edge number 0 */
14880     buffer->start=0;
14881     buffer->end=1;
14882     buffer->next=buffer;
14883     buffer->prev=buffer;
14884     buffer->invers=edges+1;
14885     buffer->min=buffer;
14886 
14887     buffer++; /* edge number 1 */
14888     buffer->start=1;
14889     buffer->end=0;
14890     buffer->next=edges+2;
14891     buffer->prev=edges+2;
14892     buffer->invers=edges;
14893     buffer->min=edges;
14894 
14895     buffer++; /* edge number 2 */
14896     buffer->start=1;
14897     buffer->end=2;
14898     buffer->next=edges+1;
14899     buffer->prev=edges+1;
14900     buffer->invers=edges+3;
14901     buffer->min=buffer;
14902 
14903     buffer++; /* edge number 3 */
14904     buffer->start=2;
14905     buffer->end=1;
14906     buffer->next=buffer;
14907     buffer->prev=buffer;
14908     buffer->invers=edges+2;
14909     buffer->min=edges+2;
14910 
14911     firstedge[0]=edges;
14912     firstedge[1]=edges+1;
14913     firstedge[2]=edges+3;
14914 
14915     degree[0]=degree[2]=1;
14916     degree[1]=2;
14917 
14918     nv=3;
14919     ne=4;
14920 }
14921 
14922 /**************************************************************************/
14923 
14924 static void
initialize_quadrangulations(void)14925 initialize_quadrangulations(void)
14926 
14927 /* initialize edges for the generation of all simple quadrangulations
14928    and make the initial path P3 */
14929 
14930 {
14931     EDGE *run,*start;
14932     int n;
14933 
14934 /* Initialize the edges for operation P0. They look like
14935 
14936        a
14937       / \
14938     ?b   c    Vertex c is the new point. (a,c) and (d,c) are the
14939       \ /     new edges with a-->c taken as quadr_P0(n)
14940        d
14941 
14942 It is assumed that for 3<=n<MAXN after quadr_P0(n) there is room for 4 edges.
14943 */
14944 
14945     for (n=3; n<MAXN; n++)
14946       { run=start=quadr_P0(n);
14947         run->end=n; run->min=run;
14948         run->invers=start+1;
14949 
14950         run=start+1; run->start=n;
14951         run->prev=run->next=start+3;
14952         run->min=run->invers=start;
14953 
14954         run=start+2; run->end=n; run->min=run; run->invers=start+3;
14955 
14956         run=start+3; run->start=n; run->min=run->invers=start+2;
14957         run->prev=run->next=start+1;
14958       }
14959 
14960 /* Then initialize the edges for operation P1. They look like
14961 
14962        a
14963     ? / \
14964    --b   c--  Vertex c is the new point. (a,c) and (d,c) are the
14965     ? \ /     new edges with a-->c taken as quadr_P1(n)
14966        d
14967 
14968 It is assumed that for 5<=n<MAXN after quadr_P1(n) there is room for 4 edges.
14969 */
14970 
14971     for (n=5; n<MAXN; n++)
14972       { run=start=quadr_P1(n);
14973         run->end=n; run->min=run;
14974         run->invers=start+1;
14975 
14976         run=start+1; run->start=n;
14977         run->min=run->invers=start; run->prev=start+3;
14978 
14979         run=start+2; run->end=n; run->min=run; run->invers=start+3;
14980 
14981         run=start+3; run->start=n; run->min=run->invers=start+2;
14982         run->next=start+1;
14983       }
14984 
14985    make_P3();
14986 }
14987 
14988 /*******************************************************************/
14989 
14990 static EDGE
extend_quadr_P0(EDGE * e1)14991 *extend_quadr_P0(EDGE *e1)
14992 
14993 /* extends a graph in the way given by the type P0 extension for
14994    quadrangulations.
14995 
14996    The new path is inserted on the left of e1.
14997 
14998    It returns the directed edge starting at the new vertex with the
14999    new face on its left.
15000 
15001    In the picture: e1=b->a, the edge c->a is returned and
15002    vertex c is the new point nv.
15003 
15004        ?
15005        a
15006       / \
15007     ?b   c?
15008       \ /
15009        d
15010        ?
15011 */
15012 
15013 {
15014   register EDGE *start, *dummy, *dummy2;
15015   int buffer;
15016 
15017   start=quadr_P0(nv);
15018 
15019   degree[nv]=2;
15020 
15021   buffer=e1->end;
15022   dummy=e1->invers; dummy2=dummy->prev;
15023   start->start=buffer;
15024   start->next=dummy; dummy->prev=start;
15025   start->prev=dummy2; dummy2->next=start;
15026   degree[buffer]++;
15027 
15028   start++;
15029   firstedge[nv]=start;
15030   start->end=buffer;
15031 
15032   e1=e1->next;
15033   start++;
15034   buffer=e1->end;
15035   dummy=e1->invers; dummy2=dummy->next;
15036   start->start=buffer;
15037   start->next=dummy2; dummy2->prev=start;
15038   start->prev=dummy; dummy->next=start;
15039   degree[buffer]++;
15040 
15041   (start+1)->end=buffer;
15042 
15043   nv++; ne+=4;
15044 
15045   return (start-1);
15046 }
15047 
15048 /**************************************************************************/
15049 
15050 static void
reduce_quadr_P0(EDGE * e)15051 reduce_quadr_P0(EDGE *e)
15052 
15053 /* reduces a graph previously extended by the P0 extension for
15054    quadrangulations. The edge e must be the reference edge
15055    returned by the expansion routine.
15056 */
15057 
15058 {
15059   register EDGE *dummy, *dummy2;
15060   int buffer;
15061 
15062   nv--; ne-=4;
15063 
15064   dummy=e->invers;
15065   dummy2=dummy->next;
15066   dummy=dummy->prev;
15067 
15068   dummy->next=dummy2; dummy2->prev=dummy;
15069   buffer=dummy->start;
15070   firstedge[buffer]=dummy; degree[buffer]--;
15071 
15072   dummy=e->prev->invers;
15073   dummy2=dummy->next;
15074   dummy=dummy->prev;
15075 
15076   dummy->next=dummy2; dummy2->prev=dummy;
15077   buffer=dummy->start;
15078   firstedge[buffer]=dummy; degree[buffer]--;
15079 }
15080 
15081 /*******************************************************************/
15082 
15083 static EDGE
extend_quadr_P1(EDGE * e)15084 *extend_quadr_P1(EDGE *e)
15085 
15086 /* extends a graph in the way given by the type P1 extension for
15087    3-connected quadrangulations.
15088 
15089    It returns the directed edge characterizing this operation.
15090 */
15091 
15092 {
15093   register EDGE *e1, *e1i, *e2, *e3, *e3i, *e4, *start, *dummy;
15094   int end1, end2, center;
15095 
15096   center=e->start;
15097   e1=e->prev;
15098   e1i=e1->invers;
15099   e2=e1i->prev;
15100   end1=e2->start;
15101 
15102   e3=e->next;
15103   e3i=e3->invers;
15104   e4=e3i->next;
15105   end2=e4->start;
15106 
15107   e1->next=e3; e3->prev=e1; degree[center]--; firstedge[center]=e1;
15108 
15109   start=quadr_P1(nv);
15110   dummy=start+1;
15111   start->start=dummy->end=end1;
15112   degree[end1]++;
15113   start->next=e1i; e1i->prev=start;
15114   start->prev=e2; e2->next=start;
15115 
15116   dummy->next=e; e->prev=dummy;
15117 
15118   start+=2; dummy=start+1;
15119   start->start=dummy->end=end2;
15120   degree[end2]++;
15121   e3i->next=start; start->prev=e3i;
15122   e4->prev=start; start->next=e4;
15123 
15124   e->next=dummy; dummy->prev=e;
15125 
15126   degree[nv]=3; e->start=e->invers->end=nv; firstedge[nv]=e;
15127   nv++; ne+=4;
15128 
15129   return (e);
15130 }
15131 
15132 /**************************************************************************/
15133 
15134 static void
reduce_quadr_P1(EDGE * e)15135 reduce_quadr_P1(EDGE *e)
15136 
15137 /* reduces a graph previously extended by the type P1 extension for
15138    3-connected quadrangulations. The edge e must be the reference edge
15139 */
15140 
15141 {
15142   register EDGE *e1, *e1i, *e2, *e3, *e3i, *e4;
15143   int end1, end2, center;
15144 
15145   nv--; ne-=4;
15146 
15147   e2=e->prev->invers->prev;
15148   end1=e2->start;
15149   e1i=e2->next->next;
15150   e1=e1i->invers;
15151   center=e1->start;
15152   e3=e1->next;
15153   e3i=e3->invers;
15154   e4=e3i->next->next;
15155   end2=e4->start;
15156 
15157   e2->next=e1i; e1i->prev=e2; firstedge[end1]=e2; degree[end1]--;
15158   e1->next=e; e->prev=e1; e->next=e3; e3->prev=e;
15159   e->start=e->invers->end=center; degree[center]++;
15160   e3i->next=e4; e4->prev=e3i; firstedge[end2]=e4; degree[end2]--;
15161 }
15162 
15163 /*******************************************************************/
15164 
15165 static EDGE
extend_quadr_P2(EDGE * e)15166 *extend_quadr_P2(EDGE *e)
15167 
15168 /* extends a graph in the way given by the type P2 extension for
15169    3-connected quadrangulations.
15170 
15171    It returns the directed edge characterizing this operation.
15172 */
15173 
15174 {
15175   register EDGE *e1, *e2, *e3, *e4, *e5, *e5i, *e6i, *start, *dummy;
15176   int end1, end2, end3;
15177 
15178   e=e->next;
15179   end2=e->end;
15180   e1=e->invers;
15181   e4=e1->next;
15182   e5=e1->prev;
15183   e5i=e5->invers;
15184   e6i=e5i->prev;
15185   end3=e5i->start;
15186   e3=e4->invers->next->invers;
15187   e2=e3->next;
15188   end1=e3->start;
15189 
15190   start=quadr_P2(nv);
15191   dummy=start+1;
15192   start->end=dummy->start=end3; degree[end3]++;
15193   e6i->next=e5i->prev=dummy; dummy->prev=e6i; dummy->next=e5i;
15194 
15195   dummy=start+3;
15196   dummy->start=(dummy-1)->end=end2; firstedge[end2]=dummy;
15197   e5->next=e4->prev=dummy; dummy->next=e4; dummy->prev=e5;
15198 
15199   dummy=start+5;
15200   dummy->start=(dummy-1)->end=end1; degree[end1]++;
15201   e3->next=e2->prev=dummy; dummy->next=e2; dummy->prev=e3;
15202 
15203   dummy=start+7;
15204   e->end=e1->start=nv;
15205   start->next=dummy->prev=e1; e1->next=dummy; e1->prev=start;
15206 
15207   degree[nv]=degree[nv+1]=3;
15208   firstedge[nv]=start; firstedge[nv+1]=start+2;
15209 
15210   nv+=2; ne+=8;
15211 
15212   return start;
15213 }
15214 
15215 /*******************************************************************/
15216 
15217 static void
reduce_quadr_P2(EDGE * e)15218 reduce_quadr_P2(EDGE *e)
15219 
15220 /* reduces a P2 configuration formerly expanded by extend_quadr_P2() */
15221 
15222 {  register EDGE *e1, *e2, *e3, *e4, *e5, *e5i, *e6i;
15223    int end1, end2, end3;
15224 
15225    nv-=2; ne-=8;
15226 
15227    e1=e->next;
15228    e=e->invers;
15229    end3=e->start;
15230    e6i=e->prev; e5i=e->next;
15231    e5=e5i->invers;
15232    end2=e5->start;
15233    e4=e5->next->next;
15234    e3=e4->invers->next->invers;
15235    end1=e3->start;
15236    e2=e3->next->next;
15237    e=e1->invers;
15238 
15239    e6i->next=e5i; e5i->prev=e6i; degree[end3]--; firstedge[end3]=e5i;
15240 
15241    e5->next=e4->prev=e1; e1->next=e4; e1->prev=e5;
15242    e1->start=e->end=end2; firstedge[end2]=e1;
15243 
15244    e3->next=e2; e2->prev=e3; degree[end1]--; firstedge[end1]=e2;
15245 }
15246 
15247 /*******************************************************************/
15248 
15249 static EDGE
extend_quadr_P3(EDGE * e)15250 *extend_quadr_P3(EDGE *e)
15251 
15252 /* extends a graph in the way given by the type P3 extension for
15253    3-connected quadrangulations. That is: It inserts a square on the
15254    right hand side of e.
15255 
15256    It returns the directed edge characterizing this operation.
15257 */
15258 
15259 {
15260   register EDGE *run, *start, *dummy;
15261   int vertex;
15262 
15263   start=quadr_P3(nv);
15264 
15265   run=e->next;
15266   vertex=e->start;
15267   dummy=start+12;
15268   start->end=dummy->start=vertex; degree[vertex]++;
15269   e->next=run->prev=dummy; dummy->next=run; dummy->prev=e;
15270 
15271   e=run->invers;
15272   run=e->next;
15273   vertex=e->start;
15274   dummy=start+15;
15275   (start+10)->end=dummy->start=vertex; degree[vertex]++;
15276   e->next=run->prev=dummy; dummy->next=run; dummy->prev=e;
15277 
15278   e=run->invers;
15279   run=e->next;
15280   vertex=e->start;
15281   dummy--;
15282   (start+7)->end=dummy->start=vertex; degree[vertex]++;
15283   e->next=run->prev=dummy; dummy->next=run; dummy->prev=e;
15284 
15285   e=run->invers;
15286   run=e->next;
15287   vertex=e->start;
15288   dummy--;
15289   (start+4)->end=dummy->start=vertex; degree[vertex]++;
15290   e->next=run->prev=dummy; dummy->next=run; dummy->prev=e;
15291 
15292   firstedge[nv]=start;     degree[nv]=3;
15293   firstedge[nv+1]=start+3; degree[nv+1]=3;
15294   firstedge[nv+2]=start+6; degree[nv+2]=3;
15295   firstedge[nv+3]=start+9; degree[nv+3]=3;
15296 
15297   nv+=4; ne+=16;
15298 
15299   return (run->invers);
15300 }
15301 
15302 /*******************************************************************/
15303 
15304 static void
reduce_quadr_P3(EDGE * e)15305 reduce_quadr_P3(EDGE *e)
15306 
15307 /* Reduces the graph formerly extended by the type P3 extension for
15308    3-connected quadrangulations. That is: It removes a square on the
15309    right hand side of e.
15310 */
15311 
15312 {
15313   register EDGE *dummy;
15314   int start;
15315 
15316   nv-=4; ne-=16;
15317 
15318   dummy=e->next->next;
15319   start=e->start;
15320   degree[start]--; firstedge[start]=e;
15321   e->next=dummy; dummy->prev=e;
15322 
15323   e=dummy->invers;
15324   dummy=e->next->next;
15325   start=e->start;
15326   degree[start]--; firstedge[start]=e;
15327   e->next=dummy; dummy->prev=e;
15328 
15329   e=dummy->invers;
15330   dummy=e->next->next;
15331   start=e->start;
15332   degree[start]--; firstedge[start]=e;
15333   e->next=dummy; dummy->prev=e;
15334 
15335   e=dummy->invers;
15336   dummy=e->next->next;
15337   start=e->start;
15338   degree[start]--; firstedge[start]=e;
15339   e->next=dummy; dummy->prev=e;
15340 }
15341 
15342 /*******************************************************************/
15343 
15344 static int
will_be_3_connected(EDGE * e)15345 will_be_3_connected(EDGE *e)
15346 
15347 /* returns 1 if after performing a P1 expansion for edge e, the graph
15348    will still be 3-connected, 0 else
15349 
15350    Uses the fact that there are no 3-cycles.
15351 */
15352 
15353 {
15354   int end1, end2;
15355   EDGE *run, *last;
15356 
15357   end1=e->prev->end;
15358   end2=e->next->end;
15359 
15360   if (degree[end1]<degree[end2])
15361     { e=e->prev->invers;
15362     run=e->next; last=e->prev;
15363     /* end2 cannot be in the face left of run -- would be a double edge
15364        and for the same reason not in the face right of last */
15365     while (run!=last)
15366       { if (run->invers->prev->end==end2) return 0;
15367         run=run->next; }
15368     }
15369   else
15370     { e=e->next->invers;
15371     run=e->next; last=e->prev;
15372     while (run!=last)
15373       { if (run->invers->prev->end==end1) return 0;
15374         run=run->next; }
15375     }
15376 
15377   return 1;
15378 }
15379 
15380 /*******************************************************************/
15381 
15382 static int
legal_P1_reduction(EDGE * e)15383 legal_P1_reduction(EDGE *e)
15384 
15385 /* checks whether the edge e characterizes a legal P1-reduction.
15386    Returns 1 if yes, 0 otherwise.
15387 
15388    It is assumed that edge->start has degree 3, and that both the side
15389    vertices edge->next->end and edge->prev->end have degree at least 4.
15390 */
15391 
15392 { EDGE *run, *last;
15393  int w,w1,w2, buffer;
15394 
15395  w=e->end;
15396  run=e->next->invers->prev->invers;
15397  last=run->prev;
15398  run=run->next;
15399 
15400  do { if (run->end==w) return 0; run=run->next; } while (run!=last);
15401 
15402  e=e->invers;
15403  w1=e->next->end;
15404  w2=e->prev->end;
15405 
15406 
15407  /* OK -- then some serious tests have to be done... */
15408 
15409  run=last->next;
15410  last=last->prev;
15411 
15412  if (run->invers->prev->end==w1) return 0;
15413  /* cannot be w2 */
15414  for (run=run->next; run!=last; run=run->next)
15415    { buffer=run->invers->prev->end;
15416    if (buffer==w1) return 0;
15417    if (buffer==w2) return 0;
15418    }
15419 
15420  /* the last one cannot be w1 */
15421  if (run->invers->prev->end==w2) return 0;
15422 
15423  /* All tests successful -- no 2-cut will occur: */
15424 
15425  return 1;
15426 }
15427 
15428 /***********************************************************************/
15429 
15430 static int
legal_P1_reduction_all(EDGE * e)15431 legal_P1_reduction_all(EDGE *e)
15432 
15433 /* checks whether the edge e characterizes a legal P1-reduction.
15434    General quadrangulations version.
15435    Returns TRUE if legal, FALSE otherwise.
15436 
15437    It is assumed that edge->start has degree 3, and that there are
15438    no vertices of degree 2.
15439 */
15440 
15441 { EDGE *run, *last;
15442  int w;
15443 
15444  w=e->end;
15445  run=e->next->invers->prev->invers;
15446  last=run->prev;
15447  run=run->next;
15448 
15449  do { if (run->end==w) return FALSE; run=run->next; } while (run!=last);
15450 
15451  return TRUE;
15452 }
15453 
15454 /***********************************************************************/
15455 
15456 static int
legal_P1_reduction_min3(EDGE * e)15457 legal_P1_reduction_min3(EDGE *e)
15458 
15459 /* checks whether the edge e characterizes a legal P1-reduction.
15460    mindeg 3 version
15461    Returns TRUE if yes, FALSE otherwise.
15462 
15463    It is assumed that edge->start has degree 3, and that both the side
15464    vertices edge->next->end and edge->prev->end have degree at least 4.
15465 */
15466 
15467 { EDGE *run, *last;
15468  int w;
15469 
15470  w=e->end;
15471  run=e->next->invers->prev->invers;
15472  last=run->prev;
15473  run=run->next;
15474 
15475  do { if (run->end==w) return FALSE; run=run->next; } while (run!=last);
15476 
15477  return TRUE;
15478 }
15479 
15480 /***********************************************************************/
15481 
15482 static int
legal_P1_reduction_nf4(EDGE * e)15483 legal_P1_reduction_nf4(EDGE *e)
15484 
15485 /* checks whether the edge e characterizes a legal P1-reduction.
15486    Version for 3-connected quadrangulations without non-facial 4-cycles.
15487    Returns 1 if yes, 0 otherwise.
15488 
15489    It is assumed that edge->start has degree 3, and that both the side
15490    vertices edge->next->end and edge->prev->end have degree at least 4.
15491 */
15492 
15493 {
15494     EDGE *e1,*e1last,*e2,*e2last;
15495 
15496     if (degree[e->end] == 3) return TRUE;
15497 
15498     RESETMARKS_V;
15499 
15500     e1 = e->invers;
15501     e1last = e1->prev;
15502     e1 = e1->next->next;
15503     do
15504     {
15505 	MARK_V(e1->end);
15506 	e1 = e1->next;
15507     } while (e1 != e1last);
15508 
15509     e1 = e->next->invers->prev->invers;
15510     e1last = e1->prev;
15511     e1 = e1->next;
15512     do
15513     {
15514 	e2last = e1->invers;
15515 	e2 = e2last->next;
15516 	do
15517 	{
15518 	    if (ISMARKED_V(e2->end)) return FALSE;
15519 	    e2 = e2->next;
15520 	} while (e2 != e2last);
15521 
15522         e1 = e1->next;
15523     } while (e1 != e1last);
15524 
15525     return TRUE;
15526 }
15527 
15528 /**********************************************************************/
15529 
15530 static int
legal_P3_reduction(EDGE * e)15531 legal_P3_reduction(EDGE *e)
15532 
15533 /* checks whether the edge corresponds to a legal P3 reduction.
15534    Returns 1 if it is a legal reduction, 0 else.
15535 
15536    Again it is assumed (necessary or not) that P1 has higher priority
15537    -- the nonexistence of a P1 reduction forces some subconfiguration.
15538 
15539    Furthermore it is assumed that the graph inspected is not the cube.
15540 */
15541 
15542 {
15543   EDGE *run, *last;
15544   int v1,v2;
15545 
15546   if (degree[e->next->end]!=3) return 0;
15547   run=e->invers->prev;
15548   if (degree[run->end]!=3) return 0;
15549   run=run->prev->invers->prev;
15550   if (degree[run->end]!=3) return 0;
15551   v1=run->start;
15552    run=run->prev->invers->prev;
15553   if (degree[run->end]!=3) return 0;
15554   v2=run->start;
15555 
15556   /* OK -- we have an "inserted square" on the right hand side */
15557 
15558   /* Test whether opposite vertices share a face */
15559 
15560   last=e->prev;
15561   run=e->next->next->next;
15562   while (run!=last)
15563     { if (run->invers->prev->end==v1) return 0;
15564     run=run->next; }
15565 
15566   e=e->invers;
15567   last=e->prev->prev->prev;
15568   run=e->next;
15569   while (run!=last)
15570     { if (run->invers->prev->end==v2) return 0;
15571     run=run->next; }
15572 
15573   return 1;
15574 }
15575 
15576 /*******************************************************************/
15577 
15578 static int
legal_P3_reduction_min3(EDGE * e)15579 legal_P3_reduction_min3(EDGE *e)
15580 
15581 /* checks whether the edge corresponds to a legal P3 reduction.
15582    Returns 1 if it is a legal reduction, 0 else.
15583    mindeg 3 version
15584 
15585    Again it is assumed (necessary or not) that P1 has higher priority
15586    -- the nonexistence of a P1 reduction forces some subconfiguration.
15587 
15588    Furthermore it is assumed that the graph inspected is not the cube.
15589 */
15590 
15591 {
15592   EDGE *run;
15593 
15594   if (degree[e->next->end]!=3) return 0;
15595   run=e->invers->prev;
15596   if (degree[run->end]!=3) return 0;
15597   run=run->prev->invers->prev;
15598   if (degree[run->end]!=3) return 0;
15599   run=run->prev->invers->prev;
15600   if (degree[run->end]!=3) return 0;
15601 
15602   return 1;
15603 }
15604 
15605 /****************************************************************************/
15606 
15607 static void
find_extensions_quad(int nbtot,int nbop,EDGE * extP1[],int * nextP1,EDGE * extP3[],int * nextP3,EDGE * lastP1)15608 find_extensions_quad(int nbtot, int nbop, EDGE *extP1[], int *nextP1,
15609    EDGE *extP3[], int *nextP3, EDGE *lastP1)
15610 
15611 /* Determine the inequivalent places to make extensions, for the
15612    3-connected quadrangulations.  The results are put in the arrays
15613    extP1[0..*nextP1-1], etc..
15614    nbtot and nbop are the usual group parameters.
15615    If lastA != NULL, this graph was made with an P1-operation and lastP1
15616    is its reference edge.  If lastP1 == NULL, it wasn't made with P1.
15617 */
15618 
15619 {
15620     EDGE *e,*ee,*elast;
15621     EDGE **nb,**nb0,**nblim,**nboplim;
15622     int i,k;
15623     int maxdeg,vx;
15624 
15625     if (nbtot == 1)
15626     {
15627      /* P1 extension for trivial group */
15628 
15629 	RESETMARKS_V;
15630 	if (lastP1 != NULL)
15631 	{
15632 	    maxdeg = degree[lastP1->end];
15633 	    MARK_V(lastP1->start);
15634 	    MARK_V(lastP1->next->invers->prev->end);
15635 	    vx = lastP1->end;
15636 	}
15637 	else
15638 	{
15639 	    vx = -1;
15640 	    maxdeg = 0;
15641 	}
15642 
15643         k = 0;
15644 	for (i = 0; i < nv; ++i)
15645 	if (degree[i] >= 4)
15646 	{
15647 	    e = elast = firstedge[i];
15648 	    if (i == vx)
15649 	        do
15650 	        {
15651 		    if (will_be_3_connected(e)) extP1[k++] = e;
15652 		    e = e->next;
15653 	        } while (e != elast);
15654 	    else
15655 		do
15656 	        {
15657 		    if (ISMARKED_V(e->prev->end) || ISMARKED_V(e->next->end)
15658                                                   || degree[e->end] >= maxdeg)
15659 		    {
15660 		        if (will_be_3_connected(e)) extP1[k++] = e;
15661 		    }
15662 		    e = e->next;
15663 	        } while (e != elast);
15664 	}
15665 
15666 	*nextP1 = k;
15667 
15668      /* P3 extension for trivial group */
15669 
15670 	if (nv <= maxnv-4)
15671 	{
15672 	    k = 0;
15673 	    RESETMARKS;
15674 
15675 	    for (i = 0; i < nv; ++i)
15676             {
15677                 e = elast = firstedge[i];
15678                 do
15679                 {
15680                     if (!ISMARKEDLO(e))
15681 		    {
15682 		        extP3[k++] = e;
15683 		        MARKLO(e);
15684 		        ee = e->invers->prev;
15685 		        MARKLO(ee);
15686 		        ee = ee->invers->prev;
15687 		        MARKLO(ee);
15688 		        ee = ee->invers->prev;
15689 		        MARKLO(ee);
15690 		    }
15691                     e = e->next;
15692                 } while (e != elast);
15693             }
15694   	    *nextP3 = k;
15695 	}
15696 	else
15697 	    *nextP3 = 0;
15698     }
15699     else
15700     {
15701 	nboplim = (EDGE**)numbering[nbop==0?nbtot:nbop];
15702         nblim = (EDGE**)numbering[nbtot];
15703 	nb0 = (EDGE**)numbering[0];
15704 
15705 	for (i = 0; i < ne; ++i) nb0[i]->index = i;
15706 
15707      /* P1 extensions for non-trivial group */
15708 	k = 0;
15709 	RESETMARKS;
15710 
15711 	for (i = 0; i < nv; ++i)
15712 	if (degree[i] >= 4)
15713 	{
15714 	    e = elast = firstedge[i];
15715 	    do
15716 	    {
15717 		if (!ISMARKEDLO(e) && will_be_3_connected(e))
15718 		{
15719 		    extP1[k++] = e;
15720 		    for (nb = nb0+e->index+MAXE; nb < nblim; nb += MAXE)
15721 			MARKLO(*nb);
15722 		}
15723 		e = e->next;
15724 	    } while (e != elast);
15725 	}
15726 	*nextP1 = k;
15727 
15728      /* P3 extensions for non-trivial group */
15729 
15730 	if (nv <= maxnv-4)
15731 	{
15732 	    RESETMARKS;
15733 	    k = 0;
15734             for (i = 0; i < nv; ++i)
15735             {
15736                 e = elast = firstedge[i];
15737                 do
15738                 {
15739                     if (!ISMARKEDLO(e))
15740                     {
15741                         extP3[k++] = e;
15742 		        ee = e;
15743 		        do
15744 		        {
15745 			    for (nb = nb0+ee->index; nb < nboplim; nb += MAXE)
15746 			        MARKLO(*nb);
15747 			    for ( ; nb < nblim; nb += MAXE)
15748 			        MARKLO((*nb)->invers);
15749 		            ee = ee->invers->prev;
15750 		        } while (ee != e);
15751                     }
15752                     e = e->next;
15753                 } while (e != elast);
15754             }
15755             *nextP3 = k;
15756 	}
15757 	else
15758 	    *nextP3 = 0;
15759     }
15760 }
15761 
15762 /****************************************************************************/
15763 
15764 static void
find_extensions_quad_all(int nbtot,int nbop,EDGE * extP0[],int * nextP0,EDGE * extP1[],int * nextP1)15765 find_extensions_quad_all(int nbtot, int nbop, EDGE *extP0[], int *nextP0,
15766    EDGE *extP1[], int *nextP1)
15767 
15768 /* Determine the inequivalent places to make extensions, for general
15769    quadrangulations.  The results are put in the arrays
15770    extP0[0..*nextP0-1] and extP1[0..*nextP1-1].
15771    nbtot and nbop are the usual group parameters.
15772 */
15773 
15774 {
15775     EDGE *e,*elast;
15776     EDGE **nb,**nb0,**nblim,**nboplim;
15777     int i,j,k,l,x,y;
15778     int deg2;
15779 #define VCOLP0(i,j) (degree[i]<degree[j] ? \
15780  (degree[j]<<10)+degree[i] : (degree[i]<<10)+degree[j])
15781 
15782     if (degree[nv-1] == 2)
15783     {
15784 	x = firstedge[nv-1]->end;
15785 	y = firstedge[nv-1]->next->end;
15786     }
15787     else
15788         x = -1;
15789 
15790     deg2 = 0;
15791     for (i = nv; --i >= 0 && deg2 < 3;)
15792 	if (degree[i] == 2) ++deg2;
15793 
15794     if (nbtot == 1)
15795     {
15796      /* P0 extension for trivial group */
15797 
15798         RESETMARKS;
15799 	k = 0;
15800 	for (l = 0; l < nv; ++l)
15801 	{
15802 	    e = elast = firstedge[l];
15803 	    do
15804 	    {
15805 		if (!ISMARKEDLO(e))
15806 		{
15807 		    i = e->end;
15808 		    j = e->next->end;
15809 		    if (x < 0 || i == nv-1 || j == nv-1)
15810 		        extP0[k++] = e;
15811 		    else
15812 		    {
15813 	    		++degree[i]; ++degree[j];
15814 			if (VCOLP0(i,j) >= VCOLP0(x,y)) extP0[k++] = e;
15815 	    		--degree[i]; --degree[j];
15816 		    }
15817 		    MARKLO(e->next->invers->next->invers);
15818 		}
15819 		e = e->next;
15820 	    } while (e != elast);
15821 	}
15822 
15823 	*nextP0 = k;
15824 
15825      /* P1 extension for trivial group */
15826 
15827 	if (deg2 > 2)
15828 	    *nextP1 = 0;
15829 	else
15830 	{
15831             k = 0;
15832 	    for (i = 0; i < nv; ++i)
15833 	    if (degree[i] >= 4)
15834 	    {
15835 	        e = elast = firstedge[i];
15836 	        do
15837 	        {
15838 		    if ((degree[e->prev->end]==2)
15839 					+(degree[e->next->end]==2) == deg2)
15840 			extP1[k++] = e;
15841 		    e = e->next;
15842 	        } while (e != elast);
15843 	    }
15844 
15845 	    *nextP1 = k;
15846 	}
15847     }
15848     else
15849     {
15850 	nboplim = (EDGE**)numbering[nbop==0?nbtot:nbop];
15851         nblim = (EDGE**)numbering[nbtot];
15852 	nb0 = (EDGE**)numbering[0];
15853 
15854 	for (i = 0; i < ne; ++i) nb0[i]->index = i;
15855 
15856      /* P0 extensions for non-trivial group */
15857 
15858 	k = 0;
15859 	RESETMARKS;
15860 
15861 	for (l = 0; l < ne; ++l)
15862 	    if (!ISMARKED(nb0[l]))
15863 	    {
15864 		e = nb0[l];
15865 		i = e->end;
15866 		j = e->next->end;
15867 		if (x < 0 || i == nv-1 || j == nv-1)
15868 		    extP0[k++] = e;
15869 		else
15870 		{
15871 		    ++degree[i]; ++degree[j];
15872 		    if (VCOLP0(i,j) >= VCOLP0(x,y)) extP0[k++] = e;
15873 		    --degree[i]; --degree[j];
15874 		}
15875 		for (nb = nb0+l+MAXE; nb < nboplim; nb += MAXE)
15876 		    MARKLO(*nb);
15877                 for ( ; nb < nblim; nb += MAXE)
15878 		    MARKLO((*nb)->invers->next->invers);
15879 		for (nb = nb0+(nb0[l]->next->invers->next->invers->index);
15880 			                           nb < nboplim; nb += MAXE)
15881 		    MARKLO(*nb);
15882 		for ( ; nb < nblim; nb += MAXE)
15883                     MARKLO((*nb)->invers->next->invers);
15884 	    }
15885 
15886 	*nextP0 = k;
15887 
15888      /* P1 extensions for non-trivial group */
15889 
15890 	if (deg2 > 2)
15891 	    *nextP1 = 0;
15892 	else
15893 	{
15894 	    k = 0;
15895 	    RESETMARKS;
15896 
15897 	    for (i = 0; i < nv; ++i)
15898 	    if (degree[i] >= 4)
15899 	    {
15900 	        e = elast = firstedge[i];
15901 	        do
15902 	        {
15903 		    if (!ISMARKEDLO(e))
15904 		    {
15905 			if ((degree[e->prev->end]==2)
15906 					+(degree[e->next->end]==2) == deg2)
15907 		            extP1[k++] = e;
15908 		        for (nb = nb0+e->index+MAXE; nb < nblim; nb += MAXE)
15909 			    MARKLO(*nb);
15910 		    }
15911 		    e = e->next;
15912 	        } while (e != elast);
15913 	    }
15914 
15915 	    *nextP1 = k;
15916 	}
15917     }
15918 }
15919 
15920 /****************************************************************************/
15921 
15922 static void
find_extensions_quad_min3(int nbtot,int nbop,EDGE * extP1[],int * nextP1,EDGE * extP3[],int * nextP3,EDGE * lastP1)15923 find_extensions_quad_min3(int nbtot, int nbop, EDGE *extP1[], int *nextP1,
15924    EDGE *extP3[], int *nextP3, EDGE *lastP1)
15925 
15926 /* Determine the inequivalent places to make extensions, for the
15927    quadrangulations with mindeg 3.  The results are put in the arrays
15928    extP1[0..*nextP1-1], etc..
15929    nbtot and nbop are the usual group parameters.
15930    If lastA != NULL, this graph was made with an P1-operation and lastP1
15931    is its reference edge.  If lastP1 == NULL, it wasn't made with P1.
15932 */
15933 
15934 {
15935     EDGE *e,*ee,*elast;
15936     EDGE **nb,**nb0,**nblim,**nboplim;
15937     int i,k;
15938     int maxdeg,vx;
15939 
15940     if (nbtot == 1)
15941     {
15942      /* P1 extension for trivial group */
15943 
15944 	RESETMARKS_V;
15945 	if (lastP1 != NULL)
15946 	{
15947 	    maxdeg = degree[lastP1->end];
15948 	    MARK_V(lastP1->start);
15949 	    MARK_V(lastP1->next->invers->prev->end);
15950 	    vx = lastP1->end;
15951 	}
15952 	else
15953 	{
15954 	    vx = -1;
15955 	    maxdeg = 0;
15956 	}
15957 
15958         k = 0;
15959 	for (i = 0; i < nv; ++i)
15960 	if (degree[i] >= 4)
15961 	{
15962 	    e = elast = firstedge[i];
15963 	    if (i == vx)
15964 	        do
15965 	        {
15966 		    extP1[k++] = e;
15967 		    e = e->next;
15968 	        } while (e != elast);
15969 	    else
15970 		do
15971 	        {
15972 		    if (ISMARKED_V(e->prev->end) || ISMARKED_V(e->next->end)
15973                                                   || degree[e->end] >= maxdeg)
15974 		    {
15975 		        extP1[k++] = e;
15976 		    }
15977 		    e = e->next;
15978 	        } while (e != elast);
15979 	}
15980 
15981 	*nextP1 = k;
15982 
15983      /* P3 extension for trivial group */
15984 
15985 	if (nv <= maxnv-4)
15986 	{
15987 	    k = 0;
15988 	    RESETMARKS;
15989 
15990 	    for (i = 0; i < nv; ++i)
15991             {
15992                 e = elast = firstedge[i];
15993                 do
15994                 {
15995                     if (!ISMARKEDLO(e))
15996 		    {
15997 		        extP3[k++] = e;
15998 		        MARKLO(e);
15999 		        ee = e->invers->prev;
16000 		        MARKLO(ee);
16001 		        ee = ee->invers->prev;
16002 		        MARKLO(ee);
16003 		        ee = ee->invers->prev;
16004 		        MARKLO(ee);
16005 		    }
16006                     e = e->next;
16007                 } while (e != elast);
16008             }
16009   	    *nextP3 = k;
16010 	}
16011 	else
16012 	    *nextP3 = 0;
16013     }
16014     else
16015     {
16016 	nboplim = (EDGE**)numbering[nbop==0?nbtot:nbop];
16017         nblim = (EDGE**)numbering[nbtot];
16018 	nb0 = (EDGE**)numbering[0];
16019 
16020 	for (i = 0; i < ne; ++i) nb0[i]->index = i;
16021 
16022      /* P1 extensions for non-trivial group */
16023 	k = 0;
16024 	RESETMARKS;
16025 
16026 	for (i = 0; i < nv; ++i)
16027 	if (degree[i] >= 4)
16028 	{
16029 	    e = elast = firstedge[i];
16030 	    do
16031 	    {
16032 		if (!ISMARKEDLO(e))
16033 		{
16034 		    extP1[k++] = e;
16035 		    for (nb = nb0+e->index+MAXE; nb < nblim; nb += MAXE)
16036 			MARKLO(*nb);
16037 		}
16038 		e = e->next;
16039 	    } while (e != elast);
16040 	}
16041 	*nextP1 = k;
16042 
16043      /* P3 extensions for non-trivial group */
16044 
16045 	if (nv <= maxnv-4)
16046 	{
16047 	    RESETMARKS;
16048 	    k = 0;
16049             for (i = 0; i < nv; ++i)
16050             {
16051                 e = elast = firstedge[i];
16052                 do
16053                 {
16054                     if (!ISMARKEDLO(e))
16055                     {
16056                         extP3[k++] = e;
16057 		        ee = e;
16058 		        do
16059 		        {
16060 			    for (nb = nb0+ee->index; nb < nboplim; nb += MAXE)
16061 			        MARKLO(*nb);
16062 			    for ( ; nb < nblim; nb += MAXE)
16063 			        MARKLO((*nb)->invers);
16064 		            ee = ee->invers->prev;
16065 		        } while (ee != e);
16066                     }
16067                     e = e->next;
16068                 } while (e != elast);
16069             }
16070             *nextP3 = k;
16071 	}
16072 	else
16073 	    *nextP3 = 0;
16074     }
16075 }
16076 
16077 /****************************************************************************/
16078 
16079 static void
find_extensions_quad_nf4(int nbtot,int nbop,EDGE * extP1[],int * nextP1,EDGE * lastP1)16080 find_extensions_quad_nf4(int nbtot, int nbop,
16081                          EDGE *extP1[], int *nextP1, EDGE *lastP1)
16082 
16083 /* Determine the inequivalent places to make extensions, for the
16084    3-connected quadrangulations without non-facial 4-cycles.
16085    The results are put in the arrays extP1[0..*nextP1-1], etc..
16086    nbtot and nbop are the usual group parameters.
16087    If lastA != NULL, this graph was made with an P1-operation and lastP1
16088    is its reference edge.  If lastP1 == NULL, it wasn't made with P1.
16089 */
16090 
16091 {
16092     EDGE *e,*elast;
16093     EDGE **nb,**nb0,**nblim;
16094     int i,k;
16095     int maxdeg,vx;
16096 
16097     if (nbtot == 1)
16098     {
16099      /* P1 extension for trivial group */
16100 
16101 	RESETMARKS_V;
16102 	if (lastP1 != NULL)
16103 	{
16104 	    maxdeg = degree[lastP1->end];
16105 	    MARK_V(lastP1->start);
16106 	    MARK_V(lastP1->next->invers->prev->end);
16107 	    vx = lastP1->end;
16108 	}
16109 	else
16110 	{
16111 	    vx = -1;
16112 	    maxdeg = 0;
16113 	}
16114 
16115         k = 0;
16116 	for (i = 0; i < nv; ++i)
16117 	if (degree[i] >= 4)
16118 	{
16119 	    e = elast = firstedge[i];
16120 	    if (i == vx)
16121 	        do
16122 	        {
16123 		    extP1[k++] = e;
16124 		    e = e->next;
16125 	        } while (e != elast);
16126 	    else
16127 		do
16128 	        {
16129 		    if (ISMARKED_V(e->prev->end) || ISMARKED_V(e->next->end)
16130                                                   || degree[e->end] >= maxdeg)
16131 		    {
16132 		        extP1[k++] = e;
16133 		    }
16134 		    e = e->next;
16135 	        } while (e != elast);
16136 	}
16137 
16138 	*nextP1 = k;
16139     }
16140     else
16141     {
16142         nblim = (EDGE**)numbering[nbtot];
16143 	nb0 = (EDGE**)numbering[0];
16144 
16145 	for (i = 0; i < ne; ++i) nb0[i]->index = i;
16146 
16147      /* P1 extensions for non-trivial group */
16148 	k = 0;
16149 	RESETMARKS;
16150 
16151 	for (i = 0; i < nv; ++i)
16152 	if (degree[i] >= 4)
16153 	{
16154 	    e = elast = firstedge[i];
16155 	    do
16156 	    {
16157 		if (!ISMARKEDLO(e))
16158 		{
16159 		    extP1[k++] = e;
16160 		    for (nb = nb0+e->index+MAXE; nb < nblim; nb += MAXE)
16161 			MARKLO(*nb);
16162 		}
16163 		e = e->next;
16164 	    } while (e != elast);
16165 	}
16166 	*nextP1 = k;
16167     }
16168 }
16169 
16170 /****************************************************************************/
16171 
16172 static int
has_quadr_P0(void)16173 has_quadr_P0(void)
16174 
16175 /* Test whether there is a legal P1 reduction */
16176 
16177 {
16178     int i;
16179 
16180     for (i = nv; --i >= 0; )
16181         if (degree[i] == 2) return TRUE;
16182 
16183     return FALSE;
16184 }
16185 
16186 /****************************************************************************/
16187 
16188 static int
has_quadr_P1(void)16189 has_quadr_P1(void)
16190 
16191 /* Test whether there is a legal P1 reduction */
16192 
16193 {
16194     int i;
16195     EDGE *e,*elast;
16196 
16197     for (i = 0; i < nv; ++i)
16198     if (degree[i] == 3)
16199     {
16200 	e = elast = firstedge[i];
16201 	do
16202 	{
16203 	    if (degree[e->next->end] >= 4 && degree[e->prev->end] >= 4
16204 				      && legal_P1_reduction(e)) return TRUE;
16205 	    e = e->next;
16206 	} while (e != elast);
16207     }
16208 
16209     return FALSE;
16210 }
16211 
16212 /****************************************************************************/
16213 
16214 static int
has_quadr_P1_min3(void)16215 has_quadr_P1_min3(void)
16216 
16217 /* Test whether there is a legal P1 reduction, mindeg3 version.
16218    It is enough that there is a vertex of degree 3 with at least
16219    two neighbours of degree at least 4.
16220 */
16221 
16222 {
16223     int i,n3;
16224     EDGE *e;
16225 
16226     for (i = 0; i < nv; ++i)
16227     if (degree[i] == 3)
16228     {
16229         e = firstedge[i];
16230 	n3 = 0;
16231 	if (degree[e->end] == 3) ++n3;
16232 	e = e->next;
16233 	if (degree[e->end] == 3) ++n3;
16234 	e = e->next;
16235 	if (degree[e->end] == 3) ++n3;
16236 
16237 	if (n3 <= 1) return TRUE;
16238     }
16239 
16240     return FALSE;
16241 }
16242 
16243 /****************************************************************************/
16244 
16245 static void
quadr_P1_legal(EDGE * ref,EDGE * good_or[],int * ngood_or,int * ngood_ref,EDGE * good_mir[],int * ngood_mir,int * ngood_mir_ref,EDGE * prevP1[],int nprevP1,EDGE ** hint)16246 quadr_P1_legal(EDGE *ref, EDGE *good_or[], int *ngood_or, int *ngood_ref,
16247                EDGE *good_mir[], int *ngood_mir, int *ngood_mir_ref,
16248                EDGE *prevP1[], int nprevP1, EDGE **hint)
16249 
16250 /* The P1-operation with reference edge *ref has just been performed.
16251    prevP1[0..nprevP1-1] are all earlier P1s since the last P2 or P3.
16252    hint (unless it is NULL) is a suggestion for a P1-reduction that
16253    might be better than ref.
16254    Make a list in good_or[0..*ngood_or-1] of the reference edges of
16255    legal P1-reductions (oriented editions) that might be canonical,
16256    with the first *ngood_ref of those being ref.
16257    Make a list in good_mir[0..*ngood_mir-1] of the
16258    reference edges of legal four-reductions (mirror-image editions)
16259    that might be canonical, with the first *ngood_mir_ref of those being
16260    ref->next.
16261    *ngood_ref and *ngood_mir_ref might each be 0-1.  If they are
16262    both 0, nothing else need be correct.
16263    All the edges in good_or[] and good_mir[] must start with the same
16264    vertex degree and end with the same vertex degree (actually, colour
16265    as passed to canon_edge_oriented).
16266    P1-reductions have a priority (colour) based on the degrees of the
16267    end vertex and two side vertices.  It cannot be changed without
16268    changing find_extensions_quad too.
16269 */
16270 
16271 {
16272     EDGE *e,*ee,*elast;
16273     int maxdeg;
16274     int col,maxcol;
16275     int i,nor,nmir;
16276 
16277 #define QORCOL(e) (((long)degree[e->prev->end]<<10)+(long)degree[e->next->end])
16278 #define QMIRCOL(e) (((long)degree[e->next->end]<<10)+(long)degree[e->prev->end])
16279 
16280     RESETMARKS;
16281     nor = nmir = 0;
16282 
16283     maxdeg = degree[ref->end];
16284     maxcol = QORCOL(ref);
16285     col = QMIRCOL(ref);
16286     if (col < maxcol)
16287         good_or[nor++] = ref;
16288     else if (col == maxcol)
16289     {
16290 	good_or[nor++] = ref;
16291 	good_mir[nmir++] = ref;
16292     }
16293     else
16294     {
16295 	maxcol = col;
16296 	good_mir[nmir++] = ref;
16297     }
16298 
16299     *ngood_ref = nor;
16300     *ngood_mir_ref = nmir;
16301 
16302     MARKLO(ref->invers);
16303 
16304     e = *hint;
16305     if (e && !ISMARKEDLO(e->invers)
16306              && degree[e->start] == 3 && degree[e->end] >= maxdeg
16307 	     && degree[e->next->end] >= 4 && degree[e->prev->end] >= 4
16308              && legal_P1_reduction(e))
16309     {
16310         if (degree[e->end] > maxdeg)
16311         {
16312             *ngood_ref = *ngood_mir_ref = 0;
16313             return;
16314         }
16315         else
16316         {
16317             col = QORCOL(e);
16318             if (col > maxcol)
16319             {
16320                 *ngood_ref = *ngood_mir_ref = 0;
16321                 return;
16322             }
16323             else if (col == maxcol)
16324                 good_or[nor++] = e;
16325 
16326             col = QMIRCOL(e);
16327             if (col > maxcol)
16328             {
16329                 *ngood_ref = *ngood_mir_ref = 0;
16330                 return;
16331             }
16332             else if (col == maxcol)
16333                 good_mir[nmir++] = e;
16334         }
16335         MARKLO(e->invers);
16336     }
16337 
16338     for (i = nprevP1; --i >= 0; )
16339     {
16340 	e = prevP1[i];
16341 	if (!ISMARKEDLO(e->invers) && degree[e->end] >= maxdeg
16342                  && degree[e->start] == 3
16343 		 && degree[e->next->end] >= 4 && degree[e->prev->end] >= 4
16344                  && legal_P1_reduction(e))
16345 	{
16346 	    if (degree[e->end] > maxdeg)
16347 	    {
16348 		*ngood_ref = *ngood_mir_ref = 0;
16349 		return;
16350 	    }
16351 	    else
16352 	    {
16353                 col = QORCOL(e);
16354                 if (col > maxcol)
16355                 {
16356                     *ngood_ref = *ngood_mir_ref = 0;
16357                     return;
16358                 }
16359                 else if (col == maxcol)
16360                     good_or[nor++] = e;
16361 
16362                 col = QMIRCOL(e);
16363                 if (col > maxcol)
16364                 {
16365                     *ngood_ref = *ngood_mir_ref = 0;
16366                     return;
16367                 }
16368                  else if (col == maxcol)
16369                      good_mir[nmir++] = e;
16370 	    }
16371 	}
16372 	MARKLO(e->invers);
16373     }
16374 
16375     if (nor > *ngood_ref || nmir > *ngood_mir_ref)
16376         prune_oriented_lists(good_or,&nor,ngood_ref,
16377                              good_mir,&nmir,ngood_mir_ref);
16378 
16379     if (*ngood_ref == 0 && *ngood_mir_ref == 0) return;
16380 
16381     for (i = 0; i < nv; ++i)
16382         if (degree[i] > maxdeg)
16383         {
16384 	    e = elast = firstedge[i];
16385             do
16386             {
16387 		if (!ISMARKEDLO(e) && degree[e->end] == 3)
16388                 {
16389 		    ee = e->invers;
16390 		    if (degree[ee->next->end] >= 4
16391                                 && degree[ee->prev->end] >= 4
16392                                 && legal_P1_reduction(ee))
16393 		    {
16394                         *ngood_ref = *ngood_mir_ref = 0;
16395 		        *hint = e;
16396                         return;
16397 		    }
16398                 }
16399 	        e = e->next;
16400 	    } while (e != elast);
16401         }
16402         else if (degree[i] == maxdeg)
16403         {
16404             e = elast = firstedge[i];
16405             do
16406             {
16407 		ee = e->invers;
16408                 if (degree[e->end] == 3 && !ISMARKEDLO(e)
16409                         && degree[ee->next->end] >= 4
16410                         && degree[ee->prev->end] >= 4
16411                         && legal_P1_reduction(ee))
16412                 {
16413                     col = QORCOL(e->invers);
16414                     if (col > maxcol)
16415                     {
16416                         *ngood_ref = *ngood_mir_ref = 0;
16417 		        *hint = e;
16418                         return;
16419                     }
16420                     else if (col == maxcol)
16421                         good_or[nor++] = e->invers;
16422 
16423                     col = QMIRCOL(e->invers);
16424                     if (col > maxcol)
16425                     {
16426                         *ngood_ref = *ngood_mir_ref = 0;
16427 		        *hint = e;
16428                         return;
16429                     }
16430                     else if (col == maxcol)
16431                         good_mir[nmir++] = e->invers;
16432                 }
16433                 e = e->next;
16434             } while (e != elast);
16435         }
16436 
16437     if (nor > *ngood_ref || nmir > *ngood_mir_ref)
16438         prune_oriented_lists(good_or,&nor,ngood_ref,
16439                              good_mir,&nmir,ngood_mir_ref);
16440 
16441     *ngood_or = nor;
16442     *ngood_mir = nmir;
16443 }
16444 
16445 /****************************************************************************/
16446 
16447 static void
quadr_P1_legal_min3(EDGE * ref,EDGE * good_or[],int * ngood_or,int * ngood_ref,EDGE * good_mir[],int * ngood_mir,int * ngood_mir_ref,EDGE * prevP1[],int nprevP1,EDGE ** hint)16448 quadr_P1_legal_min3(EDGE *ref, EDGE *good_or[], int *ngood_or, int *ngood_ref,
16449                EDGE *good_mir[], int *ngood_mir, int *ngood_mir_ref,
16450                EDGE *prevP1[], int nprevP1, EDGE **hint)
16451 
16452 /* The P1-operation with reference edge *ref has just been performed.
16453    prevP1[0..nprevP1-1] are all earlier P1s since the last P2 or P3.
16454    hint (unless it is NULL) is a suggestion for a P1-reduction that
16455    might be better than ref.
16456    Make a list in good_or[0..*ngood_or-1] of the reference edges of
16457    legal P1-reductions (oriented editions) that might be canonical,
16458    with the first *ngood_ref of those being ref.
16459    Make a list in good_mir[0..*ngood_mir-1] of the
16460    reference edges of legal four-reductions (mirror-image editions)
16461    that might be canonical, with the first *ngood_mir_ref of those being
16462    ref->next.
16463    *ngood_ref and *ngood_mir_ref might each be 0-1.  If they are
16464    both 0, nothing else need be correct.
16465    All the edges in good_or[] and good_mir[] must start with the same
16466    vertex degree and end with the same vertex degree (actually, colour
16467    as passed to canon_edge_oriented).
16468    P1-reductions have a priority (colour) based on the degrees of the
16469    end vertex and two side vertices.  It cannot be changed without
16470    changing find_extensions_quad too.
16471 
16472    mindeg 3 version
16473 */
16474 
16475 {
16476     EDGE *e,*ee,*elast;
16477     int maxdeg;
16478     int col,maxcol;
16479     int i,nor,nmir;
16480 
16481 #define QORCOL(e) (((long)degree[e->prev->end]<<10)+(long)degree[e->next->end])
16482 #define QMIRCOL(e) (((long)degree[e->next->end]<<10)+(long)degree[e->prev->end])
16483 
16484     RESETMARKS;
16485     nor = nmir = 0;
16486 
16487     maxdeg = degree[ref->end];
16488     maxcol = QORCOL(ref);
16489     col = QMIRCOL(ref);
16490     if (col < maxcol)
16491         good_or[nor++] = ref;
16492     else if (col == maxcol)
16493     {
16494 	good_or[nor++] = ref;
16495 	good_mir[nmir++] = ref;
16496     }
16497     else
16498     {
16499 	maxcol = col;
16500 	good_mir[nmir++] = ref;
16501     }
16502 
16503     *ngood_ref = nor;
16504     *ngood_mir_ref = nmir;
16505 
16506     MARKLO(ref->invers);
16507 
16508     e = *hint;
16509     if (e && !ISMARKEDLO(e->invers)
16510              && degree[e->start] == 3 && degree[e->end] > maxdeg
16511 	     && degree[e->next->end] >= 4 && degree[e->prev->end] >= 4
16512              && legal_P1_reduction_min3(e))
16513     {
16514         if (degree[e->end] > maxdeg)
16515         {
16516             *ngood_ref = *ngood_mir_ref = 0;
16517             return;
16518         }
16519         else
16520         {
16521             col = QORCOL(e);
16522             if (col > maxcol)
16523             {
16524                 *ngood_ref = *ngood_mir_ref = 0;
16525                 return;
16526             }
16527             else if (col == maxcol)
16528                 good_or[nor++] = e;
16529 
16530             col = QMIRCOL(e);
16531             if (col > maxcol)
16532             {
16533                 *ngood_ref = *ngood_mir_ref = 0;
16534                 return;
16535             }
16536             else if (col == maxcol)
16537                 good_mir[nmir++] = e;
16538         }
16539         MARKLO(e->invers);
16540     }
16541 
16542     for (i = nprevP1; --i >= 0; )
16543     {
16544 	e = prevP1[i];
16545 	if (!ISMARKEDLO(e->invers) && degree[e->end] >= maxdeg
16546                  && degree[e->start] == 3
16547 		 && degree[e->next->end] >= 4 && degree[e->prev->end] >= 4
16548                  && legal_P1_reduction_min3(e))
16549 	{
16550 	    if (degree[e->end] > maxdeg)
16551 	    {
16552 		*ngood_ref = *ngood_mir_ref = 0;
16553 		return;
16554 	    }
16555 	    else
16556 	    {
16557                 col = QORCOL(e);
16558                 if (col > maxcol)
16559                 {
16560                     *ngood_ref = *ngood_mir_ref = 0;
16561                     return;
16562                 }
16563                 else if (col == maxcol)
16564                     good_or[nor++] = e;
16565 
16566                 col = QMIRCOL(e);
16567                 if (col > maxcol)
16568                 {
16569                     *ngood_ref = *ngood_mir_ref = 0;
16570                     return;
16571                 }
16572                  else if (col == maxcol)
16573                      good_mir[nmir++] = e;
16574 	    }
16575 	}
16576 	MARKLO(e->invers);
16577     }
16578 
16579     if (nor > *ngood_ref || nmir > *ngood_mir_ref)
16580         prune_oriented_lists(good_or,&nor,ngood_ref,
16581                              good_mir,&nmir,ngood_mir_ref);
16582 
16583     if (*ngood_ref == 0 && *ngood_mir_ref == 0) return;
16584 
16585     for (i = 0; i < nv; ++i)
16586         if (degree[i] > maxdeg)
16587         {
16588 	    e = elast = firstedge[i];
16589             do
16590             {
16591 		if (!ISMARKEDLO(e) && degree[e->end] == 3)
16592                 {
16593 		    ee = e->invers;
16594 		    if (degree[ee->next->end] >= 4
16595                                 && degree[ee->prev->end] >= 4
16596                                 && legal_P1_reduction_min3(ee))
16597 		    {
16598                         *ngood_ref = *ngood_mir_ref = 0;
16599 		        *hint = e;
16600                         return;
16601 		    }
16602                 }
16603 	        e = e->next;
16604 	    } while (e != elast);
16605         }
16606         else if (degree[i] == maxdeg)
16607         {
16608             e = elast = firstedge[i];
16609             do
16610             {
16611 		ee = e->invers;
16612                 if (degree[e->end] == 3 && !ISMARKEDLO(e)
16613                         && degree[ee->next->end] >= 4
16614                         && degree[ee->prev->end] >= 4
16615                         && legal_P1_reduction_min3(ee))
16616                 {
16617                     col = QORCOL(e->invers);
16618                     if (col > maxcol)
16619                     {
16620                         *ngood_ref = *ngood_mir_ref = 0;
16621 		        *hint = e;
16622                         return;
16623                     }
16624                     else if (col == maxcol)
16625                         good_or[nor++] = e->invers;
16626 
16627                     col = QMIRCOL(e->invers);
16628                     if (col > maxcol)
16629                     {
16630                         *ngood_ref = *ngood_mir_ref = 0;
16631 		        *hint = e;
16632                         return;
16633                     }
16634                     else if (col == maxcol)
16635                         good_mir[nmir++] = e->invers;
16636                 }
16637                 e = e->next;
16638             } while (e != elast);
16639         }
16640 
16641     if (nor > *ngood_ref || nmir > *ngood_mir_ref)
16642         prune_oriented_lists(good_or,&nor,ngood_ref,
16643                              good_mir,&nmir,ngood_mir_ref);
16644 
16645     *ngood_or = nor;
16646     *ngood_mir = nmir;
16647 }
16648 
16649 /****************************************************************************/
16650 
16651 static void
quadr_P0_legal_all(EDGE * ref,EDGE * good_or[],int * ngood_or,int * ngood_ref,EDGE * good_mir[],int * ngood_mir,int * ngood_mir_ref)16652 quadr_P0_legal_all(EDGE *ref, EDGE *good_or[], int *ngood_or, int *ngood_ref,
16653            EDGE *good_mir[], int *ngood_mir, int *ngood_mir_ref)
16654 
16655 /* The P0-operation with reference edge *ref has just been performed.
16656    Make a list in good_or[0..*ngood_or-1] of the reference edges of
16657    legal P1-reductions (oriented editions) that might be canonical,
16658    with the first *ngood_ref of those being ref.
16659    Make a list in good_mir[0..*ngood_mir-1] of the
16660    reference edges of legal four-reductions (mirror-image editions)
16661    that might be canonical, with the first *ngood_mir_ref of those being
16662    ref->next.
16663    *ngood_ref and *ngood_mir_ref might each be 0-1.  If they are
16664    both 0, nothing else need be correct.
16665    All the edges in good_or[] and good_mir[] must start with the same
16666    vertex degree and end with the same vertex degree (actually, colour
16667    as passed to canon_edge_oriented).
16668    P1-reductions have a priority (colour) based on the degrees of the
16669    end vertex and two side vertices.  It cannot be changed without
16670    changing find_extensions_quad too.
16671 
16672    version for general quadrangulations
16673 */
16674 
16675 {
16676     EDGE *e;
16677     int col,col2,maxcol,maxcol2;
16678     int i,nor,nmir;
16679     int d1,d2,d3,d4;
16680 
16681 #define VCOLPD(di,dj) (di<dj ? (dj<<10)+di : (di<<10)+dj)
16682 
16683     nor = nmir = 0;
16684 
16685     d1 = degree[ref->end];
16686     d2 = degree[ref->next->end];
16687     d3 = degree[ref->invers->next->end];
16688     d4 = degree[ref->invers->prev->end];
16689 
16690     maxcol = VCOLPD(d1,d2);
16691     maxcol2 = VCOLPD(d3,d4);
16692 
16693     if (d1 >= d2)
16694     {
16695         if (d3 >= d4) good_or[nor++] = ref;
16696         if (d4 >= d3) good_mir[nmir++] = ref;
16697     }
16698     if (d2 >= d1)
16699     {
16700         if (d4 >= d3) good_or[nor++] = ref->next;
16701         if (d3 >= d4) good_mir[nmir++] = ref->next;
16702     }
16703 
16704     *ngood_ref = nor;
16705     *ngood_mir_ref = nmir;
16706 
16707     for (i = nv-1; --i >= 0; )
16708         if (degree[i] == 2)
16709         {
16710 	    e = firstedge[i];
16711     	    d1 = degree[e->end];
16712     	    d2 = degree[e->next->end];
16713 	    col = VCOLPD(d1,d2);
16714 	    if (col > maxcol)
16715 	    {
16716 		*ngood_ref = *ngood_mir_ref = 0;
16717 		return;
16718 	    }
16719 	    else if (col == maxcol)
16720 	    {
16721     		d3 = degree[e->invers->next->end];
16722     		d4 = degree[e->invers->prev->end];
16723 		col2 = VCOLPD(d3,d4);
16724 
16725 		if (col2 > maxcol2)
16726 		{
16727                     *ngood_ref = *ngood_mir_ref = 0;
16728                     return;
16729                 }
16730                 else if (col2 == maxcol2)
16731                 {
16732     		    if (d1 >= d2)
16733     		    {
16734         	        if (d3 >= d4) good_or[nor++] = e;
16735         	        if (d4 >= d3) good_mir[nmir++] = e;
16736     		    }
16737     		    if (d2 >= d1)
16738     		    {
16739         	        if (d4 >= d3) good_or[nor++] = e->next;
16740         	        if (d3 >= d4) good_mir[nmir++] = e->next;
16741     		    }
16742 		}
16743 	    }
16744         }
16745 
16746     if (nor > *ngood_ref || nmir > *ngood_mir_ref)
16747         prune_oriented_lists(good_or,&nor,ngood_ref,
16748                              good_mir,&nmir,ngood_mir_ref);
16749 
16750     *ngood_or = nor;
16751     *ngood_mir = nmir;
16752 }
16753 
16754 /****************************************************************************/
16755 
16756 static void
quadr_P1_legal_all(EDGE * ref,EDGE * good_or[],int * ngood_or,int * ngood_ref,EDGE * good_mir[],int * ngood_mir,int * ngood_mir_ref)16757 quadr_P1_legal_all(EDGE *ref, EDGE *good_or[], int *ngood_or, int *ngood_ref,
16758                EDGE *good_mir[], int *ngood_mir, int *ngood_mir_ref)
16759 
16760 /* The P1-operation with reference edge *ref has just been performed.
16761    Make a list in good_or[0..*ngood_or-1] of the reference edges of
16762    legal P1-reductions (oriented editions) that might be canonical,
16763    with the first *ngood_ref of those being ref.
16764    Make a list in good_mir[0..*ngood_mir-1] of the
16765    reference edges of legal four-reductions (mirror-image editions)
16766    that might be canonical, with the first *ngood_mir_ref of those being
16767    ref->next.
16768    *ngood_ref and *ngood_mir_ref might each be 0-1.  If they are
16769    both 0, nothing else need be correct.
16770    All the edges in good_or[] and good_mir[] must start with the same
16771    vertex degree and end with the same vertex degree (actually, colour
16772    as passed to canon_edge_oriented).
16773    P1-reductions have a priority (colour) based on the degrees of the
16774    end vertex and two side vertices.  It cannot be changed without
16775    changing find_extensions_quad too.
16776 
16777    version for general quadrangulations
16778    assumes no vertices of degree 2
16779 */
16780 
16781 {
16782     EDGE *e,*ee,*elast;
16783     int maxdeg;
16784     int col,maxcol;
16785     int i,nor,nmir;
16786 
16787 #define QORCOL(e) (((long)degree[e->prev->end]<<10)+(long)degree[e->next->end])
16788 #define QMIRCOL(e) (((long)degree[e->next->end]<<10)+(long)degree[e->prev->end])
16789 
16790     RESETMARKS;
16791     nor = nmir = 0;
16792 
16793     maxdeg = degree[ref->end];
16794     maxcol = QORCOL(ref);
16795     col = QMIRCOL(ref);
16796     if (col < maxcol)
16797         good_or[nor++] = ref;
16798     else if (col == maxcol)
16799     {
16800 	good_or[nor++] = ref;
16801 	good_mir[nmir++] = ref;
16802     }
16803     else
16804     {
16805 	maxcol = col;
16806 	good_mir[nmir++] = ref;
16807     }
16808 
16809     *ngood_ref = nor;
16810     *ngood_mir_ref = nmir;
16811 
16812     MARKLO(ref->invers);
16813 
16814     if (nor > *ngood_ref || nmir > *ngood_mir_ref)
16815         prune_oriented_lists(good_or,&nor,ngood_ref,
16816                              good_mir,&nmir,ngood_mir_ref);
16817 
16818     if (*ngood_ref == 0 && *ngood_mir_ref == 0) return;
16819 
16820     for (i = 0; i < nv; ++i)
16821         if (degree[i] > maxdeg)
16822         {
16823 	    e = elast = firstedge[i];
16824             do
16825             {
16826 		if (!ISMARKEDLO(e) && degree[e->end] == 3)
16827                 {
16828 		    ee = e->invers;
16829 		    if (legal_P1_reduction_all(ee))
16830 		    {
16831                         *ngood_ref = *ngood_mir_ref = 0;
16832                         return;
16833 		    }
16834                 }
16835 	        e = e->next;
16836 	    } while (e != elast);
16837         }
16838         else if (degree[i] == maxdeg)
16839         {
16840             e = elast = firstedge[i];
16841             do
16842             {
16843 		ee = e->invers;
16844                 if (degree[e->end] == 3 && !ISMARKEDLO(e)
16845                         && legal_P1_reduction_all(ee))
16846                 {
16847                     col = QORCOL(e->invers);
16848                     if (col > maxcol)
16849                     {
16850                         *ngood_ref = *ngood_mir_ref = 0;
16851                         return;
16852                     }
16853                     else if (col == maxcol)
16854                         good_or[nor++] = e->invers;
16855 
16856                     col = QMIRCOL(e->invers);
16857                     if (col > maxcol)
16858                     {
16859                         *ngood_ref = *ngood_mir_ref = 0;
16860                         return;
16861                     }
16862                     else if (col == maxcol)
16863                         good_mir[nmir++] = e->invers;
16864                 }
16865                 e = e->next;
16866             } while (e != elast);
16867         }
16868 
16869     if (nor > *ngood_ref || nmir > *ngood_mir_ref)
16870         prune_oriented_lists(good_or,&nor,ngood_ref,
16871                              good_mir,&nmir,ngood_mir_ref);
16872 
16873     *ngood_or = nor;
16874     *ngood_mir = nmir;
16875 }
16876 
16877 /****************************************************************************/
16878 
16879 static void
quadr_P1_legal_nf4(EDGE * ref,EDGE * good_or[],int * ngood_or,int * ngood_ref,EDGE * good_mir[],int * ngood_mir,int * ngood_mir_ref,EDGE * prevP1[],int nprevP1,EDGE ** hint)16880 quadr_P1_legal_nf4(EDGE *ref, EDGE *good_or[], int *ngood_or, int *ngood_ref,
16881                EDGE *good_mir[], int *ngood_mir, int *ngood_mir_ref,
16882                EDGE *prevP1[], int nprevP1, EDGE **hint)
16883 
16884 /* The P1-operation with reference edge *ref has just been performed.
16885    prevP1[0..nprevP1-1] are all earlier P1s since the last P2 or P3.
16886    hint (unless it is NULL) is a suggestion for a P1-reduction that
16887    might be better than ref.
16888    Make a list in good_or[0..*ngood_or-1] of the reference edges of
16889    legal P1-reductions (oriented editions) that might be canonical,
16890    with the first *ngood_ref of those being ref.
16891    Make a list in good_mir[0..*ngood_mir-1] of the
16892    reference edges of legal four-reductions (mirror-image editions)
16893    that might be canonical, with the first *ngood_mir_ref of those being
16894    ref->next.
16895    *ngood_ref and *ngood_mir_ref might each be 0-1.  If they are
16896    both 0, nothing else need be correct.
16897    All the edges in good_or[] and good_mir[] must start with the same
16898    vertex degree and end with the same vertex degree (actually, colour
16899    as passed to canon_edge_oriented).
16900    P1-reductions have a priority (colour) based on the degrees of the
16901    end vertex and two side vertices.  It cannot be changed without
16902    changing find_extensions_quad too.
16903 
16904    Version for 3-connected quadrangulations without non-facial 4-cycles.
16905 */
16906 
16907 {
16908     EDGE *e,*ee,*elast;
16909     int maxdeg;
16910     int col,maxcol;
16911     int i,nor,nmir;
16912 
16913 #define QORCOL(e) (((long)degree[e->prev->end]<<10)+(long)degree[e->next->end])
16914 #define QMIRCOL(e) (((long)degree[e->next->end]<<10)+(long)degree[e->prev->end])
16915 
16916     RESETMARKS;
16917     nor = nmir = 0;
16918 
16919     maxdeg = degree[ref->end];
16920     maxcol = QORCOL(ref);
16921     col = QMIRCOL(ref);
16922     if (col < maxcol)
16923         good_or[nor++] = ref;
16924     else if (col == maxcol)
16925     {
16926 	good_or[nor++] = ref;
16927 	good_mir[nmir++] = ref;
16928     }
16929     else
16930     {
16931 	maxcol = col;
16932 	good_mir[nmir++] = ref;
16933     }
16934 
16935     *ngood_ref = nor;
16936     *ngood_mir_ref = nmir;
16937 
16938     MARKLO(ref->invers);
16939 
16940     e = *hint;
16941     if (e && !ISMARKEDLO(e->invers)
16942              && degree[e->start] == 3 && degree[e->end] > maxdeg
16943 	     && degree[e->next->end] >= 4 && degree[e->prev->end] >= 4
16944              && legal_P1_reduction_nf4(e))
16945     {
16946         if (degree[e->end] > maxdeg)
16947         {
16948             *ngood_ref = *ngood_mir_ref = 0;
16949             return;
16950         }
16951         else
16952         {
16953             col = QORCOL(e);
16954             if (col > maxcol)
16955             {
16956                 *ngood_ref = *ngood_mir_ref = 0;
16957                 return;
16958             }
16959             else if (col == maxcol)
16960                 good_or[nor++] = e;
16961 
16962             col = QMIRCOL(e);
16963             if (col > maxcol)
16964             {
16965                 *ngood_ref = *ngood_mir_ref = 0;
16966                 return;
16967             }
16968             else if (col == maxcol)
16969                 good_mir[nmir++] = e;
16970         }
16971         MARKLO(e->invers);
16972     }
16973 
16974     for (i = nprevP1; --i >= 0; )
16975     {
16976 	e = prevP1[i];
16977 	if (!ISMARKEDLO(e->invers) && degree[e->end] >= maxdeg
16978                  && degree[e->start] == 3
16979 		 && degree[e->next->end] >= 4 && degree[e->prev->end] >= 4
16980                  && legal_P1_reduction_nf4(e))
16981 	{
16982 	    if (degree[e->end] > maxdeg)
16983 	    {
16984 		*ngood_ref = *ngood_mir_ref = 0;
16985 		return;
16986 	    }
16987 	    else
16988 	    {
16989                 col = QORCOL(e);
16990                 if (col > maxcol)
16991                 {
16992                     *ngood_ref = *ngood_mir_ref = 0;
16993                     return;
16994                 }
16995                 else if (col == maxcol)
16996                     good_or[nor++] = e;
16997 
16998                 col = QMIRCOL(e);
16999                 if (col > maxcol)
17000                 {
17001                     *ngood_ref = *ngood_mir_ref = 0;
17002                     return;
17003                 }
17004                  else if (col == maxcol)
17005                      good_mir[nmir++] = e;
17006 	    }
17007 	}
17008 	MARKLO(e->invers);
17009     }
17010 
17011     if (nor > *ngood_ref || nmir > *ngood_mir_ref)
17012         prune_oriented_lists(good_or,&nor,ngood_ref,
17013                              good_mir,&nmir,ngood_mir_ref);
17014 
17015     if (*ngood_ref == 0 && *ngood_mir_ref == 0) return;
17016 
17017     for (i = 0; i < nv; ++i)
17018         if (degree[i] > maxdeg)
17019         {
17020 	    e = elast = firstedge[i];
17021             do
17022             {
17023 		if (!ISMARKEDLO(e) && degree[e->end] == 3)
17024                 {
17025 		    ee = e->invers;
17026 		    if (degree[ee->next->end] >= 4
17027                                 && degree[ee->prev->end] >= 4
17028                                 && legal_P1_reduction_nf4(ee))
17029 		    {
17030                         *ngood_ref = *ngood_mir_ref = 0;
17031 		        *hint = e;
17032                         return;
17033 		    }
17034                 }
17035 	        e = e->next;
17036 	    } while (e != elast);
17037         }
17038         else if (degree[i] == maxdeg)
17039         {
17040             e = elast = firstedge[i];
17041             do
17042             {
17043 		ee = e->invers;
17044                 if (degree[e->end] == 3 && !ISMARKEDLO(e)
17045                         && degree[ee->next->end] >= 4
17046                         && degree[ee->prev->end] >= 4
17047                         && legal_P1_reduction_nf4(ee))
17048                 {
17049                     col = QORCOL(e->invers);
17050                     if (col > maxcol)
17051                     {
17052                         *ngood_ref = *ngood_mir_ref = 0;
17053 		        *hint = e;
17054                         return;
17055                     }
17056                     else if (col == maxcol)
17057                         good_or[nor++] = e->invers;
17058 
17059                     col = QMIRCOL(e->invers);
17060                     if (col > maxcol)
17061                     {
17062                         *ngood_ref = *ngood_mir_ref = 0;
17063 		        *hint = e;
17064                         return;
17065                     }
17066                     else if (col == maxcol)
17067                         good_mir[nmir++] = e->invers;
17068                 }
17069                 e = e->next;
17070             } while (e != elast);
17071         }
17072 
17073     if (nor > *ngood_ref || nmir > *ngood_mir_ref)
17074         prune_oriented_lists(good_or,&nor,ngood_ref,
17075                              good_mir,&nmir,ngood_mir_ref);
17076 
17077     *ngood_or = nor;
17078     *ngood_mir = nmir;
17079 }
17080 
17081 /****************************************************************************/
17082 
17083 static void
quadr_P3_legal(EDGE * ref,EDGE * good_or[],int * ngood_or,int * ngood_ref,EDGE * good_mir[],int * ngood_mir,int * ngood_mir_ref)17084 quadr_P3_legal(EDGE *ref, EDGE *good_or[], int *ngood_or, int *ngood_ref,
17085                EDGE *good_mir[], int *ngood_mir, int *ngood_mir_ref)
17086 
17087 /* The P3-operation with reference edge *ref has just been performed.
17088    Make a list in good_or[0..*ngood_or-1] of the reference edges of
17089    legal P3-reductions (oriented editions) that might be canonical,
17090    with the first *ngood_ref of those being ref.
17091    Make a list in good_mir[0..*ngood_mir-1] of the
17092    reference edges of legal four-reductions (mirror-image editions)
17093    that might be canonical, with the first *ngood_mir_ref of those being
17094    ref->next.
17095    *ngood_ref and *ngood_mir_ref might each be 0-4.  If they are
17096    both 0, nothing else need be correct.
17097    All the edges in good_or[] and good_mir[] must start with the same
17098    vertex degree and end with the same vertex degree (actually, colour
17099    as passed to canon_edge_oriented).
17100    P3-reductions have a priority (colour) based on the degrees of the
17101    end vertex and two side vertices.  It cannot be changed without
17102    changing find_extensions_quad too.
17103 */
17104 
17105 {
17106     EDGE *e,*elast,*e1;
17107     int maxdeg;
17108     int col,col1,col2,maxcol;
17109     int i,j,nor,nmir;
17110 
17111 #define QORCOL3(e) \
17112       (((long)degree[e->next->end]<<10)+(long)degree[e->prev->end])
17113 #define QMIRCOL3(e) \
17114       (((long)degree[e->prev->end]<<10)+(long)degree[e->next->end])
17115 
17116     RESETMARKS;
17117 
17118     maxdeg = 0;
17119     e1 = ref->next;
17120 
17121     for (j = 0; j < 4; ++j)
17122     {
17123 	if (degree[e1->start] > maxdeg)
17124 	{
17125 	    maxdeg = degree[e1->start];
17126 	    maxcol = QORCOL3(e1);
17127             nor = nmir = 0;
17128 	    good_or[nor++] = e1;
17129 
17130 	    col = QMIRCOL3(e1);
17131 	    if (col > maxcol)
17132 	    {
17133 		nor = nmir = 0;
17134 		good_mir[nmir++] = e1;
17135 		maxcol = col;
17136 	    }
17137 	    else if (col == maxcol)
17138 		good_mir[nmir++] = e1;
17139 	}
17140 	else if (degree[e1->start] == maxdeg)
17141 	{
17142 	    col = QORCOL3(e1);
17143 	    if (col > maxcol)
17144             {
17145                 nor = nmir = 0;
17146                 good_or[nor++] = e1;
17147                 maxcol = col;
17148             }
17149             else if (col == maxcol)
17150                 good_or[nor++] = e1;
17151 
17152             col = QMIRCOL3(e1);
17153             if (col > maxcol)
17154             {
17155                 nor = nmir = 0;
17156                 good_mir[nmir++] = e1;
17157                 maxcol = col;
17158             }
17159             else if (col == maxcol)
17160                 good_mir[nmir++] = e1;
17161         }
17162 
17163 	MARKLO(e1);
17164 	e1 = e1->prev->invers->prev;
17165     }
17166 
17167     *ngood_ref = nor;
17168     *ngood_mir_ref = nmir;
17169 
17170     for (i = 0; i < nv; ++i)
17171         if (degree[i] > maxdeg)
17172         {
17173 	    e = elast = firstedge[i];
17174 	    do
17175 	    {
17176 	        if (!ISMARKEDLO(e) && legal_P3_reduction(e->prev))
17177 	        {
17178 		    *ngood_ref = *ngood_mir_ref = 0;
17179 		    return;
17180 	        }
17181 		e = e->next;
17182             } while (e != elast);
17183         }
17184 	else if (degree[i] == maxdeg)
17185 	{
17186 	    e = elast = firstedge[i];
17187 	    do
17188 	    {
17189 		if (!ISMARKEDLO(e))
17190 		{
17191 		    col1 = QORCOL3(e);
17192 		    col2 = QMIRCOL3(e);
17193 		    if (col1 > maxcol || col2 > maxcol)
17194 		    {
17195 			if (legal_P3_reduction(e->prev))
17196 			{
17197                             *ngood_ref = *ngood_mir_ref = 0;
17198                             return;
17199 			}
17200 		    }
17201 		    else if ((col1 == maxcol || col2 == maxcol)
17202 		                           && legal_P3_reduction(e->prev))
17203 		    {
17204 			if (col1 == maxcol) good_or[nor++] = e;
17205 			if (col2 == maxcol) good_mir[nmir++] = e;
17206 		    }
17207                 }
17208 	        e = e->next;
17209 	    } while (e != elast);
17210         }
17211 
17212     if (nor > *ngood_ref || nmir > *ngood_mir_ref)
17213         prune_oriented_lists(good_or,&nor,ngood_ref,
17214                              good_mir,&nmir,ngood_mir_ref);
17215 
17216     *ngood_or = nor;
17217     *ngood_mir = nmir;
17218 }
17219 
17220 /****************************************************************************/
17221 
17222 static void
quadr_P3_legal_min3(EDGE * ref,EDGE * good_or[],int * ngood_or,int * ngood_ref,EDGE * good_mir[],int * ngood_mir,int * ngood_mir_ref)17223 quadr_P3_legal_min3(EDGE *ref, EDGE *good_or[], int *ngood_or, int *ngood_ref,
17224                EDGE *good_mir[], int *ngood_mir, int *ngood_mir_ref)
17225 
17226 /* The P3-operation with reference edge *ref has just been performed.
17227    Make a list in good_or[0..*ngood_or-1] of the reference edges of
17228    legal P3-reductions (oriented editions) that might be canonical,
17229    with the first *ngood_ref of those being ref.
17230    Make a list in good_mir[0..*ngood_mir-1] of the
17231    reference edges of legal four-reductions (mirror-image editions)
17232    that might be canonical, with the first *ngood_mir_ref of those being
17233    ref->next.
17234    *ngood_ref and *ngood_mir_ref might each be 0-4.  If they are
17235    both 0, nothing else need be correct.
17236    All the edges in good_or[] and good_mir[] must start with the same
17237    vertex degree and end with the same vertex degree (actually, colour
17238    as passed to canon_edge_oriented).
17239    P3-reductions have a priority (colour) based on the degrees of the
17240    end vertex and two side vertices.  It cannot be changed without
17241    changing find_extensions_quad too.
17242 
17243    mindeg 3 version
17244 */
17245 
17246 {
17247     EDGE *e,*elast,*e1;
17248     int maxdeg;
17249     int col,col1,col2,maxcol;
17250     int i,j,nor,nmir;
17251 
17252 #define QORCOL3(e) \
17253       (((long)degree[e->next->end]<<10)+(long)degree[e->prev->end])
17254 #define QMIRCOL3(e) \
17255       (((long)degree[e->prev->end]<<10)+(long)degree[e->next->end])
17256 
17257     RESETMARKS;
17258 
17259     maxdeg = 0;
17260     e1 = ref->next;
17261 
17262     for (j = 0; j < 4; ++j)
17263     {
17264 	if (degree[e1->start] > maxdeg)
17265 	{
17266 	    maxdeg = degree[e1->start];
17267 	    maxcol = QORCOL3(e1);
17268             nor = nmir = 0;
17269 	    good_or[nor++] = e1;
17270 
17271 	    col = QMIRCOL3(e1);
17272 	    if (col > maxcol)
17273 	    {
17274 		nor = nmir = 0;
17275 		good_mir[nmir++] = e1;
17276 		maxcol = col;
17277 	    }
17278 	    else if (col == maxcol)
17279 		good_mir[nmir++] = e1;
17280 	}
17281 	else if (degree[e1->start] == maxdeg)
17282 	{
17283 	    col = QORCOL3(e1);
17284 	    if (col > maxcol)
17285             {
17286                 nor = nmir = 0;
17287                 good_or[nor++] = e1;
17288                 maxcol = col;
17289             }
17290             else if (col == maxcol)
17291                 good_or[nor++] = e1;
17292 
17293             col = QMIRCOL3(e1);
17294             if (col > maxcol)
17295             {
17296                 nor = nmir = 0;
17297                 good_mir[nmir++] = e1;
17298                 maxcol = col;
17299             }
17300             else if (col == maxcol)
17301                 good_mir[nmir++] = e1;
17302         }
17303 
17304 	MARKLO(e1);
17305 	e1 = e1->prev->invers->prev;
17306     }
17307 
17308     *ngood_ref = nor;
17309     *ngood_mir_ref = nmir;
17310 
17311     for (i = 0; i < nv; ++i)
17312         if (degree[i] > maxdeg)
17313         {
17314 	    e = elast = firstedge[i];
17315 	    do
17316 	    {
17317 	        if (!ISMARKEDLO(e) && legal_P3_reduction_min3(e->prev))
17318 	        {
17319 		    *ngood_ref = *ngood_mir_ref = 0;
17320 		    return;
17321 	        }
17322 		e = e->next;
17323             } while (e != elast);
17324         }
17325 	else if (degree[i] == maxdeg)
17326 	{
17327 	    e = elast = firstedge[i];
17328 	    do
17329 	    {
17330 		if (!ISMARKEDLO(e))
17331 		{
17332 		    col1 = QORCOL3(e);
17333 		    col2 = QMIRCOL3(e);
17334 		    if (col1 > maxcol || col2 > maxcol)
17335 		    {
17336 			if (legal_P3_reduction_min3(e->prev))
17337 			{
17338                             *ngood_ref = *ngood_mir_ref = 0;
17339                             return;
17340 			}
17341 		    }
17342 		    else if ((col1 == maxcol || col2 == maxcol)
17343 		                        && legal_P3_reduction_min3(e->prev))
17344 		    {
17345 			if (col1 == maxcol) good_or[nor++] = e;
17346 			if (col2 == maxcol) good_mir[nmir++] = e;
17347 		    }
17348                 }
17349 	        e = e->next;
17350 	    } while (e != elast);
17351         }
17352 
17353     if (nor > *ngood_ref || nmir > *ngood_mir_ref)
17354         prune_oriented_lists(good_or,&nor,ngood_ref,
17355                              good_mir,&nmir,ngood_mir_ref);
17356 
17357     *ngood_or = nor;
17358     *ngood_mir = nmir;
17359 }
17360 
17361 /****************************************************************************/
17362 
17363 static void
scanquadrangulations(int nbtot,int nbop,EDGE * spoke,int dosplit,EDGE * P1edge[],int nP1edges)17364 scanquadrangulations(int nbtot, int nbop, EDGE *spoke, int dosplit,
17365                      EDGE *P1edge[], int nP1edges)
17366 
17367 /* The main node of the recursion for 3-connected quadrangulations.
17368    As this procedure is entered, nv,ne,degree etc are set for some graph,
17369    and nbtot/nbop are the values returned by canon() for that graph.
17370    If spoke!=NULL the input is a pseudo-double wheel and this is a
17371    spoke from the rim towards the hub.
17372    If dosplit==TRUE, this is the place to do splitting (if any).
17373    Splitting is a bit more complicated because the P operation adds
17374    two vertices.
17375    P1edge[0..nP1edges-1] are edges of the graph that were reference
17376    edges for P1-operations in ancestors of this graph.  They may not
17377    be reference edges for P1-reductions now, but at least they are edges.
17378    However, if nP1edges>0, we can say that certainly P1edge[nP1edges-1]
17379    is a P1-operation that was just done.
17380 */
17381 
17382 {
17383     EDGE *firstedge_save[MAXN];
17384     EDGE *extP1[MAXE],*extP3[MAXE];
17385     EDGE *good_or[MAXE],*good_mir[MAXE];
17386     int ngood_or,ngood_mir,ngood_ref,ngood_mir_ref;
17387     int nextP1,nextP3,i;
17388     int xnbtot,xnbop;
17389     EDGE *newP1edge[MAXN],*rededge;
17390     EDGE *hint;
17391 
17392     if (nv == maxnv)
17393     {
17394 	if (pswitch) startbipscan(nbtot,nbop,3);
17395 	else         got_one(nbtot,nbop,3);
17396 	return;
17397     }
17398 
17399     if (dosplit)
17400     {
17401 #ifdef SPLITTEST
17402         ++splitcases;
17403         return;
17404 #endif
17405         if (splitcount-- != 0) return;
17406         splitcount = mod - 1;
17407 
17408         for (i = 0; i < nv; ++i) firstedge_save[i] = firstedge[i];
17409     }
17410 
17411 #ifdef PRE_FILTER_QUAD
17412     if (!(PRE_FILTER_QUAD)) return;
17413 #endif
17414 
17415 #ifndef FIND_EXTENSIONS_QUAD
17416 #define FIND_EXTENSIONS_QUAD find_extensions_quad
17417 #endif
17418 
17419     FIND_EXTENSIONS_QUAD(nbtot,nbop,extP1,&nextP1,extP3,&nextP3,
17420 				  (nP1edges==0?NULL:P1edge[nP1edges-1]));
17421 
17422     if (spoke && nv <= maxnv-2)
17423     {
17424         rededge = extend_quadr_P2(spoke);
17425 #ifdef FAST_FILTER_QUAD
17426         if (FAST_FILTER_QUAD)
17427 #endif
17428         {
17429             (void)canon(degree,numbering,&xnbtot,&xnbop);
17430             scanquadrangulations(xnbtot,xnbop,spoke,
17431                                  nv==splitlevel||nv==splitlevel+1,newP1edge,0);
17432 	}
17433         reduce_quadr_P2(rededge);
17434     }
17435 
17436     hint = NULL;
17437     for (i = 0; i < nextP1; ++i)
17438     {
17439         rededge = extend_quadr_P1(extP1[i]);
17440 #ifdef FAST_FILTER_QUAD
17441         if (FAST_FILTER_QUAD)
17442 #endif
17443         {
17444 	    quadr_P1_legal(rededge,good_or,&ngood_or,&ngood_ref,good_mir,
17445                            &ngood_mir,&ngood_mir_ref,P1edge,nP1edges,&hint);
17446             if (ngood_ref+ngood_mir_ref > 0)
17447 	    {
17448 	        if (nv == maxnv && !needgroup && ngood_or == ngood_ref
17449                                               && ngood_mir == ngood_mir_ref)
17450 		    got_one(1,1,3);
17451 	        else if (ngood_or+ngood_mir==1)
17452 	        {
17453     		    P1edge[nP1edges] = rededge;
17454     		    scanquadrangulations(1,1,NULL,nv==splitlevel,
17455 						    P1edge,nP1edges+1);
17456 	        }
17457 	        else if (canon_edge_oriented(good_or,ngood_or,ngood_ref,
17458                                              good_mir,ngood_mir,ngood_mir_ref,
17459                                              degree,numbering,&xnbtot,&xnbop))
17460 	        {
17461 		    P1edge[nP1edges] = rededge;
17462 	            scanquadrangulations(xnbtot,xnbop,NULL,nv==splitlevel,
17463                                                            P1edge,nP1edges+1);
17464 	        }
17465 	    }
17466 	}
17467 	reduce_quadr_P1(rededge);
17468     }
17469 
17470     for (i = 0; i < nextP3; ++i)
17471     {
17472         rededge = extend_quadr_P3(extP3[i]);
17473 #ifdef FAST_FILTER_QUAD
17474         if (FAST_FILTER_QUAD)
17475 #endif
17476         {
17477             if (!has_quadr_P1())
17478             {
17479                 quadr_P3_legal(rededge,good_or,&ngood_or,&ngood_ref,
17480                                good_mir,&ngood_mir,&ngood_mir_ref);
17481                 if (ngood_ref+ngood_mir_ref > 0
17482                     && canon_edge_oriented(good_or,ngood_or,ngood_ref,
17483                                            good_mir,ngood_mir,ngood_mir_ref,
17484                                            degree,numbering,&xnbtot,&xnbop))
17485                     scanquadrangulations(xnbtot,xnbop,NULL,
17486                                  nv>=splitlevel&&nv<=splitlevel+3,newP1edge,0);
17487             }
17488         }
17489         reduce_quadr_P3(rededge);
17490     }
17491 
17492     if (dosplit)
17493         for (i = 0; i < nv; ++i) firstedge[i] = firstedge_save[i];
17494 }
17495 
17496 /****************************************************************************/
17497 
17498 static void
scanquadrangulations_min3(int nbtot,int nbop,EDGE * spoke,int dosplit,EDGE * P1edge[],int nP1edges)17499 scanquadrangulations_min3(int nbtot, int nbop, EDGE *spoke, int dosplit,
17500                           EDGE *P1edge[], int nP1edges)
17501 
17502 /* The main node of the recursion for quadrangulations of mindeg 3.
17503    As this procedure is entered, nv,ne,degree etc are set for some graph,
17504    and nbtot/nbop are the values returned by canon() for that graph.
17505    If spoke!=NULL the input is a pseudo-double wheel and this is a
17506    spoke from the rim towards the hub.
17507    If dosplit==TRUE, this is the place to do splitting (if any).
17508    Splitting is a bit more complicated because the P operation adds
17509    two vertices.
17510    P1edge[0..nP1edges-1] are edges of the graph that were reference
17511    edges for P1-operations in ancestors of this graph.  They may not
17512    be reference edges for P1-reductions now, but at least they are edges.
17513    However, if nP1edges>0, we can say that certainly P1edge[nP1edges-1]
17514    is a P1-operation that was just done.
17515 */
17516 
17517 {
17518     EDGE *firstedge_save[MAXN];
17519     EDGE *extP1[MAXE],*extP3[MAXE];
17520     EDGE *good_or[MAXE],*good_mir[MAXE];
17521     int ngood_or,ngood_mir,ngood_ref,ngood_mir_ref;
17522     int nextP1,nextP3,i;
17523     int xnbtot,xnbop,conn;
17524     EDGE *newP1edge[MAXN],*rededge;
17525     EDGE *hint;
17526 
17527     if (nv == maxnv)
17528     {
17529         if (pswitch || xswitch) conn = con_quad();
17530         else                    conn = 2;           /* really 2 or 3 */
17531 
17532         if (pswitch) startbipscan(nbtot,nbop,conn);
17533         else         got_one(nbtot,nbop,conn);
17534         return;
17535     }
17536 
17537     if (dosplit)
17538     {
17539 #ifdef SPLITTEST
17540         ++splitcases;
17541         return;
17542 #endif
17543         if (splitcount-- != 0) return;
17544         splitcount = mod - 1;
17545 
17546         for (i = 0; i < nv; ++i) firstedge_save[i] = firstedge[i];
17547     }
17548 
17549 #ifdef PRE_FILTER_QUAD_MIN3
17550     if (!(PRE_FILTER_QUAD_MIN3)) return;
17551 #endif
17552 
17553 #ifndef FIND_EXTENSIONS_QUAD_MIN3
17554 #define FIND_EXTENSIONS_QUAD_MIN3 find_extensions_quad_min3
17555 #endif
17556 
17557     FIND_EXTENSIONS_QUAD_MIN3(nbtot,nbop,extP1,&nextP1,extP3,&nextP3,
17558 				  (nP1edges==0?NULL:P1edge[nP1edges-1]));
17559 
17560     if (spoke && nv <= maxnv-2)
17561     {
17562         rededge = extend_quadr_P2(spoke);
17563 #ifdef FAST_FILTER_QUAD_MIN3
17564         if (FAST_FILTER_QUAD_MIN3)
17565 #endif
17566         {
17567             (void)canon(degree,numbering,&xnbtot,&xnbop);
17568             scanquadrangulations_min3(xnbtot,xnbop,spoke,
17569                               nv==splitlevel||nv==splitlevel+1,newP1edge,0);
17570 	}
17571         reduce_quadr_P2(rededge);
17572     }
17573 
17574     hint = NULL;
17575     for (i = 0; i < nextP1; ++i)
17576     {
17577         rededge = extend_quadr_P1(extP1[i]);
17578 #ifdef FAST_FILTER_QUAD_MIN3
17579         if (FAST_FILTER_QUAD_MIN3)
17580 #endif
17581         {
17582 	    quadr_P1_legal_min3(rededge,good_or,&ngood_or,&ngood_ref,good_mir,
17583                            &ngood_mir,&ngood_mir_ref,P1edge,nP1edges,&hint);
17584             if (ngood_ref+ngood_mir_ref > 0)
17585 	    {
17586 	        if (nv == maxnv && !needgroup && ngood_or == ngood_ref
17587                                               && ngood_mir == ngood_mir_ref)
17588 		    got_one(1,1,3);
17589 	        else if (ngood_or+ngood_mir==1)
17590 	        {
17591     		    P1edge[nP1edges] = rededge;
17592     		    scanquadrangulations_min3(1,1,NULL,nv==splitlevel,
17593 						    P1edge,nP1edges+1);
17594 	        }
17595 	        else if (canon_edge_oriented(good_or,ngood_or,ngood_ref,
17596                                              good_mir,ngood_mir,ngood_mir_ref,
17597                                              degree,numbering,&xnbtot,&xnbop))
17598 	        {
17599 		    P1edge[nP1edges] = rededge;
17600 	            scanquadrangulations_min3(xnbtot,xnbop,NULL,nv==splitlevel,
17601                                                             P1edge,nP1edges+1);
17602 	        }
17603 	    }
17604 	}
17605 	reduce_quadr_P1(rededge);
17606     }
17607 
17608     for (i = 0; i < nextP3; ++i)
17609     {
17610         rededge = extend_quadr_P3(extP3[i]);
17611 #ifdef FAST_FILTER_QUAD_MIN3
17612         if (FAST_FILTER_QUAD_MIN3)
17613 #endif
17614         {
17615             if (!has_quadr_P1_min3())
17616             {
17617                 quadr_P3_legal_min3(rededge,good_or,&ngood_or,&ngood_ref,
17618                                good_mir,&ngood_mir,&ngood_mir_ref);
17619                 if (ngood_ref+ngood_mir_ref > 0
17620                     && canon_edge_oriented(good_or,ngood_or,ngood_ref,
17621                                            good_mir,ngood_mir,ngood_mir_ref,
17622                                            degree,numbering,&xnbtot,&xnbop))
17623                     scanquadrangulations_min3(xnbtot,xnbop,NULL,
17624                                  nv>=splitlevel&&nv<=splitlevel+3,newP1edge,0);
17625             }
17626         }
17627         reduce_quadr_P3(rededge);
17628     }
17629 
17630     if (dosplit)
17631         for (i = 0; i < nv; ++i) firstedge[i] = firstedge_save[i];
17632 }
17633 
17634 /****************************************************************************/
17635 
17636 static void
scanquadrangulations_nf4(int nbtot,int nbop,EDGE * spoke,int dosplit,EDGE * P1edge[],int nP1edges)17637 scanquadrangulations_nf4(int nbtot, int nbop, EDGE *spoke, int dosplit,
17638                           EDGE *P1edge[], int nP1edges)
17639 
17640 /* The main node of the recursion for 3-connected quadrangulations
17641    without non-facial 4-cycles.
17642    As this procedure is entered, nv,ne,degree etc are set for some graph,
17643    and nbtot/nbop are the values returned by canon() for that graph.
17644    If spoke!=NULL the input is a pseudo-double wheel and this is a
17645    spoke from the rim towards the hub.
17646    If dosplit==TRUE, this is the place to do splitting (if any).
17647    Splitting is a bit more complicated because the P operation adds
17648    two vertices.
17649    P1edge[0..nP1edges-1] are edges of the graph that were reference
17650    edges for P1-operations in ancestors of this graph.  They may not
17651    be reference edges for P1-reductions now, but at least they are edges.
17652    However, if nP1edges>0, we can say that certainly P1edge[nP1edges-1]
17653    is a P1-operation that was just done.
17654 */
17655 
17656 {
17657     EDGE *firstedge_save[MAXN];
17658     EDGE *extP1[MAXE];
17659     EDGE *good_or[MAXE],*good_mir[MAXE];
17660     int ngood_or,ngood_mir,ngood_ref,ngood_mir_ref;
17661     int nextP1,i;
17662     int xnbtot,xnbop;
17663     EDGE *newP1edge[MAXN],*rededge;
17664     EDGE *hint;
17665 
17666     if (nv == maxnv)
17667     {
17668 	got_one(nbtot,nbop,4);   /* Note connectivity is really 3 */
17669 	return;
17670     }
17671 
17672     if (dosplit)
17673     {
17674 #ifdef SPLITTEST
17675         ++splitcases;
17676         return;
17677 #endif
17678         if (splitcount-- != 0) return;
17679         splitcount = mod - 1;
17680 
17681         for (i = 0; i < nv; ++i) firstedge_save[i] = firstedge[i];
17682     }
17683 
17684 #ifdef PRE_FILTER_QUAD_NF4
17685     if (!(PRE_FILTER_QUAD_NF4)) return;
17686 #endif
17687 
17688 #ifndef FIND_EXTENSIONS_QUAD_NF4
17689 #define FIND_EXTENSIONS_QUAD_NF4 find_extensions_quad_nf4
17690 #endif
17691 
17692     FIND_EXTENSIONS_QUAD_NF4(nbtot,nbop,extP1,&nextP1,
17693 				  (nP1edges==0?NULL:P1edge[nP1edges-1]));
17694 
17695     if (spoke && nv <= maxnv-2)
17696     {
17697         rededge = extend_quadr_P2(spoke);
17698 #ifdef FAST_FILTER_QUAD_NF4
17699         if (FAST_FILTER_QUAD_NF4)
17700 #endif
17701         {
17702             (void)canon(degree,numbering,&xnbtot,&xnbop);
17703             scanquadrangulations_nf4(xnbtot,xnbop,spoke,
17704                               nv==splitlevel||nv==splitlevel+1,newP1edge,0);
17705 	}
17706         reduce_quadr_P2(rededge);
17707     }
17708 
17709     hint = NULL;
17710     for (i = 0; i < nextP1; ++i)
17711     {
17712         rededge = extend_quadr_P1(extP1[i]);
17713 #ifdef FAST_FILTER_QUAD_NF4
17714         if (FAST_FILTER_QUAD_NF4)
17715 #endif
17716         {
17717 	    quadr_P1_legal_nf4(rededge,good_or,&ngood_or,&ngood_ref,good_mir,
17718                            &ngood_mir,&ngood_mir_ref,P1edge,nP1edges,&hint);
17719             if (ngood_ref+ngood_mir_ref > 0)
17720 	    {
17721 	        if (nv == maxnv && !needgroup && ngood_or == ngood_ref
17722                                               && ngood_mir == ngood_mir_ref)
17723 		    got_one(1,1,4);
17724 	        else if (ngood_or+ngood_mir==1)
17725 	        {
17726     		    P1edge[nP1edges] = rededge;
17727     		    scanquadrangulations_nf4(1,1,NULL,nv==splitlevel,
17728 							P1edge,nP1edges+1);
17729 	        }
17730 	        else if (canon_edge_oriented(good_or,ngood_or,ngood_ref,
17731                                              good_mir,ngood_mir,ngood_mir_ref,
17732                                              degree,numbering,&xnbtot,&xnbop))
17733 	        {
17734 		    P1edge[nP1edges] = rededge;
17735 	            scanquadrangulations_nf4(xnbtot,xnbop,NULL,nv==splitlevel,
17736                                                             P1edge,nP1edges+1);
17737 	        }
17738 	    }
17739 	}
17740 	reduce_quadr_P1(rededge);
17741     }
17742 
17743     if (dosplit)
17744         for (i = 0; i < nv; ++i) firstedge[i] = firstedge_save[i];
17745 }
17746 
17747 /****************************************************************************/
17748 
17749 static void
scanquadrangulations_all(int nbtot,int nbop)17750 scanquadrangulations_all(int nbtot, int nbop)
17751 
17752 /* The main node of the recursion for general simple quadrangulations.
17753    As this procedure is entered, nv,ne,degree etc are set for some graph,
17754    and nbtot/nbop are the values returned by canon() for that graph.
17755 */
17756 
17757 {
17758     EDGE *firstedge_save[MAXN];
17759     EDGE *extP0[MAXE],*extP1[MAXE];
17760     EDGE *good_or[MAXE],*good_mir[MAXE];
17761     int ngood_or,ngood_mir,ngood_ref,ngood_mir_ref;
17762     int nextP0,nextP1,i;
17763     int xnbtot,xnbop,conn;
17764     EDGE *rededge;
17765 
17766     if (nv == maxnv)
17767     {
17768 	if (pswitch || xswitch) conn = con_quad();
17769 	else                    conn = 2;           /* really 2 or 3 */
17770 
17771 	if (pswitch) startbipscan(nbtot,nbop,conn);
17772 	else         got_one(nbtot,nbop,conn);
17773 	return;
17774     }
17775 
17776     if (nv == splitlevel)
17777     {
17778 #ifdef SPLITTEST
17779         ++splitcases;
17780         return;
17781 #endif
17782         if (splitcount-- != 0) return;
17783         splitcount = mod - 1;
17784 
17785         for (i = 0; i < nv; ++i) firstedge_save[i] = firstedge[i];
17786     }
17787 
17788 #ifdef PRE_FILTER_QUAD_ALL
17789     if (!(PRE_FILTER_QUAD_ALL)) return;
17790 #endif
17791 
17792 #ifndef FIND_EXTENSIONS_QUAD_ALL
17793 #define FIND_EXTENSIONS_QUAD_ALL find_extensions_quad_all
17794 #endif
17795 
17796     FIND_EXTENSIONS_QUAD_ALL(nbtot,nbop,extP0,&nextP0,extP1,&nextP1);
17797 
17798     for (i = 0; i < nextP0; ++i)
17799     {
17800         rededge = extend_quadr_P0(extP0[i]);
17801 #ifdef FAST_FILTER_QUAD_ALL
17802         if (FAST_FILTER_QUAD_ALL)
17803 #endif
17804         {
17805 	    quadr_P0_legal_all(rededge,good_or,&ngood_or,&ngood_ref,good_mir,
17806                                 &ngood_mir,&ngood_mir_ref);
17807             if (ngood_ref+ngood_mir_ref > 0)
17808 	    {
17809 	        if (nv == maxnv && !needgroup && ngood_or == ngood_ref
17810                                                   && ngood_mir == ngood_mir_ref)
17811 		    got_one(1,1,2);
17812 	        else if (ngood_or+ngood_mir==1)
17813     		    scanquadrangulations_all(1,1);
17814 	        else if (canon_edge_oriented(good_or,ngood_or,ngood_ref,
17815                                              good_mir,ngood_mir,ngood_mir_ref,
17816                                              degree,numbering,&xnbtot,&xnbop))
17817 	            scanquadrangulations_all(xnbtot,xnbop);
17818 	    }
17819 	}
17820 	reduce_quadr_P0(rededge);
17821     }
17822 
17823     for (i = 0; i < nextP1; ++i)
17824     {
17825         rededge = extend_quadr_P1(extP1[i]);
17826 #ifdef FAST_FILTER_QUAD_ALL
17827         if (FAST_FILTER_QUAD_ALL)
17828 #endif
17829         {
17830             if (!has_quadr_P0())
17831             {
17832                 quadr_P1_legal_all(rededge,good_or,&ngood_or,&ngood_ref,
17833                                good_mir,&ngood_mir,&ngood_mir_ref);
17834                 if (ngood_ref+ngood_mir_ref > 0
17835                     && canon_edge_oriented(good_or,ngood_or,ngood_ref,
17836                                            good_mir,ngood_mir,ngood_mir_ref,
17837                                            degree,numbering,&xnbtot,&xnbop))
17838                     scanquadrangulations_all(xnbtot,xnbop);
17839             }
17840         } reduce_quadr_P1(rededge);
17841     }
17842 
17843     if (nv == splitlevel)
17844         for (i = 0; i < nv; ++i) firstedge[i] = firstedge_save[i];
17845 }
17846 
17847 /****************************************************************************/
17848 
17849 static int
getswitchvalue(char * arg,int * pj)17850 getswitchvalue(char *arg, int *pj)
17851 
17852 /* Find integer value for switch.
17853    arg is a pointer to a command-line argument.
17854    pj is an index into arg, which is updated.
17855    The value of the switch is the function return value.
17856    For example, if arg="-xyz1432q" and *pj=3 (pointing at "z"),
17857        the value 1432 is returned and *pj=7 (pointing at "2").
17858    An absent value is equivalent to 0.
17859 */
17860 
17861 {
17862     int j,ans;
17863 
17864     ans = 0;
17865     for (j = *pj; arg[j+1] >= '0' && arg[j+1] <= '9'; ++j)
17866         ans = ans * 10 + (arg[j+1] - '0');
17867 
17868     *pj = j;
17869     return ans;
17870 }
17871 
17872 /****************************************************************************/
17873 
17874 static void
getswitchvaluelist(char * arg,int * pj,int list[],char delim[],int limit,int * count,char * sep)17875 getswitchvaluelist(char *arg, int *pj, int list[], char delim[],
17876 		   int limit, int *count, char *sep)
17877 
17878 /* Decode an integer-list argument for a switch.
17879    arg is a pointer to a command-line argument.
17880    *pj is the index of the switch name
17881      Following the switch name is a list of up to limit non-negative
17882      integers separated by characters from the string *sep.  They are
17883      found and put into list[0...] and the number of them into *count.
17884      The character before each number is put into delim[0..].
17885      The final value of *pj is the last digit of the last value.
17886      Empty values are taken as 0.
17887    For example, if arg = "az12:45-98q" and *pj=2 (at the 'z'), then
17888    the result will be list[0]=12, list[1]=45, list[2]=98,
17889                       delim[0]='z', delim[1]=':', delim[2]='-',
17890    *count=3, and *pj=10 (at the 'q').
17891 */
17892 {
17893     int j,val;
17894     int go;
17895 
17896     *count = 0;
17897     j = *pj + 1;
17898 
17899     go = TRUE;
17900     delim[0] = arg[*pj];
17901 
17902     while (go)
17903     {
17904 	if (*count >= limit)
17905 	{
17906 	    fprintf(stderr,
17907 		    ">E %s: too many values for -%c\n",cmdname,arg[*pj]);
17908 	    exit(1);
17909 	}
17910 
17911 	val = 0;
17912 	while (arg[j] >= '0' && arg[j] <= '9')
17913 	{
17914 	    val = val * 10 + (arg[j] - '0');
17915 	    ++j;
17916 	}
17917         list[(*count)++] = val;
17918 
17919 	if (arg[j] != '\0' && strchr(sep,arg[j]))
17920 	    delim[*count] = arg[j++];
17921         else
17922             go = FALSE;
17923     }
17924 
17925     *pj = j - 1;
17926 }
17927 
17928 /****************************************************************************/
17929 
17930 static void
check_switch(char sw,char * ok_switches)17931 check_switch(char sw, char *ok_switches)
17932 
17933 /* If ok_switches[sw] is zero, write an error message and exit. */
17934 
17935 {
17936     if (!OK_SWITCHES(sw))
17937     {
17938 	fprintf(stderr,">E %s:  -%c is not permitted\n",cmdname,sw);
17939 	exit(1);
17940     }
17941 }
17942 
17943 /****************************************************************************/
17944 
17945 static void
decode_command_line(int argc,char * argv[])17946 decode_command_line(int argc, char *argv[])
17947 
17948 /* Decode the command line, setting the global variables which
17949    give the switch values.  Some basic checking is done too, but
17950    the most detailed checking is done later.  If an error is
17951    found, this procedure never returns.
17952 
17953    The values for numerical parameters (minconnec, minimumdeg,
17954    edgebound[0..1], maxfacesize, polygonsize are set as -1 if the
17955    parameter is not mentioned, 0 if it appears without an integer
17956    following, and the given integer value if there is one.  Negative
17957    values are not currently allowed.
17958 */
17959 
17960 {
17961     int i,j,ares,amod;
17962     char *arg,delims[2],*as;
17963     int badargs,argsgot;
17964     int numbounds;
17965     char ok_switches[256];
17966 
17967     for (i = 0; i < argc ; ++i) fprintf(stderr,"%s ",argv[i]);
17968     fprintf(stderr,"\n");
17969 
17970     cmdname = argv[0];
17971 
17972     for (i = 0; i < 256; ++i) OK_SWITCHES(i) = 0;
17973     for (as = SWITCHES; *as != '\0'; ++as) OK_SWITCHES(*as) = 1;
17974     OK_SWITCHES('[') = OK_SWITCHES(']') = OK_SWITCHES(' ') = 0;
17975     OK_SWITCHES(':') = OK_SWITCHES('-') = OK_SWITCHES('#') = 0;
17976     for (as = SECRET_SWITCHES; *as != '\0'; ++as) OK_SWITCHES(*as) = 1;
17977 
17978     argsgot = 0;
17979     badargs = FALSE;
17980     outfilename = NULL;
17981     aswitch = FALSE;
17982     gswitch = FALSE;
17983     sswitch = FALSE;
17984     Eswitch = FALSE;
17985     Tswitch = FALSE;
17986     Gswitch = FALSE;
17987     hswitch = FALSE;
17988     oswitch = FALSE;
17989     dswitch = FALSE;
17990     tswitch = FALSE;
17991     uswitch = FALSE;
17992     vswitch = FALSE;
17993     xswitch = FALSE;
17994     pswitch = FALSE;
17995     qswitch = FALSE;
17996     Aswitch = FALSE;
17997     zeroswitch = FALSE;
17998     oneswitch = FALSE;
17999     Xswitch = 0;
18000     minconnec = -1;
18001     edgebound[0] = edgebound[1] = -1;
18002     maxfacesize = -1;
18003     polygonsize = -1;
18004     minimumdeg = -1;
18005     res = 0; mod = 1;
18006 
18007     for (i = 1; !badargs && i < argc; ++i)
18008     {
18009         arg = argv[i];
18010         if (arg[0] == '-' && arg[1] != '\0')
18011         {
18012         for (j = 1; arg[j] != '\0'; ++j)
18013 	    if (arg[j] == '\0') { }
18014 	    BOOLSWITCH('o',oswitch)
18015 	    BOOLSWITCH('d',dswitch)
18016 	    BOOLSWITCH('G',Gswitch)
18017 	    BOOLSWITCH('V',Vswitch)
18018 	    BOOLSWITCH('h',hswitch)
18019 	    BOOLSWITCH('a',aswitch)
18020 	    BOOLSWITCH('g',gswitch)
18021 	    BOOLSWITCH('s',sswitch)
18022 	    BOOLSWITCH('E',Eswitch)
18023 	    BOOLSWITCH('T',Tswitch)
18024 	    BOOLSWITCH('u',uswitch)
18025 	    BOOLSWITCH('v',vswitch)
18026 	    BOOLSWITCH('x',xswitch)
18027 	    BOOLSWITCH('t',tswitch)
18028 	    BOOLSWITCH('p',pswitch)
18029 	    BOOLSWITCH('b',bswitch)
18030 	    BOOLSWITCH('q',qswitch)
18031 	    BOOLSWITCH('A',Aswitch)
18032 	    BOOLSWITCH('0',zeroswitch)
18033 	    BOOLSWITCH('1',oneswitch)
18034 	    COUNTSWITCH('X',Xswitch)
18035 	    INTSWITCH('f',maxfacesize)
18036 	    INTSWITCH('c',minconnec)
18037 	    INTSWITCH('P',polygonsize)
18038 	    INTSWITCH('m',minimumdeg)
18039 	    else if (arg[j] == 'e')
18040 	    {
18041 		CHECKSWITCH('e');
18042 		getswitchvaluelist(arg,&j,edgebound,delims,2,&numbounds,":-");
18043 		if (numbounds == 1) edgebound[1] = edgebound[0];
18044 		if (edgebound[1] == 0) edgebound[1] = MAXE/2;
18045 	    }
18046 #ifdef PLUGIN_SWITCHES
18047             PLUGIN_SWITCHES
18048 #endif
18049             else
18050 	    {
18051 		CHECKSWITCH(arg[j]);
18052                 badargs = TRUE;
18053 	    }
18054         }
18055         else if (argsgot >= 3)
18056             badargs = TRUE;
18057         else if (argsgot == 0)
18058         {
18059             j = -1;
18060             maxnv = getswitchvalue(arg,&j);
18061             if (arg[j+1] == 'd' && arg[j+2] == '\0')
18062                 if (maxnv & 1)
18063 		{
18064 		    fprintf(stderr,">E %s: n with 'd' must be even\n",cmdname);
18065 		    exit(1);
18066 		}
18067                 else  maxnv = maxnv / 2 + 2;
18068             else if (arg[j+1] != '\0')
18069                 badargs = TRUE;
18070             ++argsgot;
18071         }
18072         else
18073         {
18074             if (arg[0] == '-')
18075             {
18076                 if (argsgot == 0) badargs = TRUE;
18077             }
18078             else if (sscanf(arg,"%d/%d",&ares,&amod) == 2)
18079             {
18080                 res = ares;
18081                 mod = amod;
18082             }
18083             else
18084                 outfilename = arg;
18085             ++argsgot;
18086         }
18087     }
18088 
18089     if (argsgot == 0) badargs = TRUE;
18090 
18091     if (badargs)
18092     {
18093         fprintf(stderr,
18094             ">E Usage: %s %s n [res/mod] [outfile]\n",cmdname,SWITCHES);
18095         exit(1);
18096     }
18097 
18098     if (res < 0 || res >= mod)
18099     {
18100         fprintf(stderr,">E %s: must have 0 <= res < mod\n",cmdname);
18101         exit(1);
18102     }
18103 
18104     if (oswitch || Vswitch || oneswitch) Gswitch = TRUE;
18105     if (oneswitch) zeroswitch = TRUE;
18106 }
18107 
18108 /****************************************************************************/
18109 
18110 static void
initialize_splitting(int minlevel,int hint,int maxlevel)18111 initialize_splitting(int minlevel, int hint, int maxlevel)
18112 
18113 /* Set splitlevel and splitcount.  minlevel and maxlevel are bounds
18114    on its value.  It must be that both minlevel and maxlevel are at
18115    least equal to the largest starting order (nv for external calls
18116    to scansimple() or similar routines), and at most equal to the
18117    smallest parent of a parent of an internal-output graph (call
18118    from scansimple() or similar to got_one() or similar).  The size
18119    of internal-output graphs is maxnv-1 for planar triangulations
18120    and maxnv for other classes.
18121 
18122    hint is a desirable value, which can be anything as the actual
18123    value used is forced between minlevel and maxlevel.  For plugins,
18124    the value of splithint is used instead if it is >= 0.
18125 
18126    In case there is no way to use splitting within those limits,
18127    it is turned off by setting splitlevel=0.  In that case only
18128    subcase 0 should produce output.
18129 
18130    Splitting occurs at the first level where nv >= splitlevel.
18131    If an operation can add k vertices, it must be that
18132    splitlevel <= maxnv - k.
18133 */
18134 {
18135     splitlevel = hint + Xswitch;
18136 #ifdef PLUGIN
18137     if (splithint >= 0) splitlevel = splithint;
18138 #endif
18139 
18140     if (splitlevel > maxlevel) splitlevel = maxlevel;
18141 
18142     if (splitlevel < minlevel && splitlevel > 0)
18143     {
18144 	if (minlevel <= maxlevel) splitlevel = minlevel;
18145 	else                      splitlevel = 0;
18146     }
18147     if (mod == 1) splitlevel = 0;
18148 
18149     splitcount = res;
18150 }
18151 
18152 /****************************************************************************/
18153 
18154 static void
open_output_file(void)18155 open_output_file(void)
18156 
18157 /* Open the output file, and write a header if one is called for.
18158    All the needed information is in global vars.  Also check if
18159    maxn is too large for this format, and set the global procedure
18160    variables write_graph() and write_dual_graph().
18161 */
18162 {
18163     int nvf;
18164 
18165     if (aswitch + gswitch + sswitch + uswitch + Eswitch + Tswitch >= 2)
18166     {
18167         fprintf(stderr,">E %s: -a, -g, -s, -u, -E, -T are incompatible\n",cmdname);
18168         exit(1);
18169     }
18170 
18171     if (!uswitch)   /*UPDATE for -E/-T and reconconsider */
18172     {
18173         nvf = dswitch ? 2*(maxnv-(polygonsize>=0))-4 : maxnv-(polygonsize>=0);
18174         if ((aswitch && nvf > 99) ||
18175             (gswitch && nvf > 255) ||
18176             (sswitch && nvf > 255) ||
18177            (!aswitch && !gswitch && !sswitch && nvf > 255))
18178         {
18179             fprintf(stderr,">E %s: n is too large for that output format\n",
18180                 cmdname);
18181             exit(1);
18182         }
18183     }
18184 
18185     msgfile = stderr;
18186     if (outfilename == NULL)
18187     {
18188         outfilename = "stdout";
18189         outfile = stdout;
18190     }
18191     else if ((outfile = fopen(outfilename,
18192         zeroswitch || oneswitch ||
18193         aswitch || Tswitch || gswitch || sswitch ? "w" : "wb")) == NULL)
18194     {
18195         fprintf(stderr,
18196           ">E %s: can't open %s for writing\n",cmdname,outfilename);
18197         perror(">E ");
18198         exit(1);
18199     }
18200 
18201     if (zeroswitch)  /* implied by oneswitch */
18202         write_graph = write_dual_graph = write_digits;
18203     else if (Tswitch)
18204 	write_graph = write_dual_graph = write_double_code;
18205     else if (aswitch)
18206     {
18207         write_graph = write_alpha;
18208         write_dual_graph = write_dual_alpha;
18209     }
18210     else if (gswitch)
18211     {
18212         write_graph = write_graph6;
18213         write_dual_graph = write_dual_graph6;
18214     }
18215     else if (sswitch)
18216     {
18217         write_graph = write_sparse6;
18218         write_dual_graph = write_dual_sparse6;
18219     }
18220     else if (Eswitch)
18221     {
18222         write_graph = write_edgecode;
18223         write_dual_graph = write_dual_edgecode;
18224     }
18225     else
18226     {
18227         write_graph = write_planar_code;
18228         write_dual_graph = write_dual_planar_code;
18229     }
18230 
18231     if (!uswitch && !aswitch && !Tswitch)
18232     {
18233         if ((!zeroswitch && !Tswitch && !hswitch && !gswitch && !sswitch && !Eswitch &&
18234 	     fwrite(PCODE,(size_t)1,PCODELEN,outfile) != PCODELEN)
18235           || (!hswitch && Eswitch &&
18236 	      fwrite(ECODE,(size_t)1,ECODELEN,outfile) != ECODELEN)
18237           || (hswitch && gswitch &&
18238 	      fwrite(G6CODE,(size_t)1,G6CODELEN,outfile) != G6CODELEN)
18239           || (hswitch && sswitch &&
18240 	      fwrite(S6CODE,(size_t)1,S6CODELEN,outfile) != S6CODELEN))
18241         {
18242             fprintf(stderr,">E %s: error writing header\n",cmdname);
18243             perror(">E ");
18244             exit(1);
18245         }
18246     }
18247 }
18248 
18249 /****************************************************************************/
18250 
18251 static void
simple_dispatch(void)18252 simple_dispatch(void)
18253 
18254 /* All the cases not handled in the other dispatch routines. */
18255 {
18256     int startingsize,nbtot,nbop,i,hint;
18257     int def[3];
18258 
18259     if (minimumdeg <= 0) minimumdeg = 3;
18260     if (minconnec <= 0)  minconnec = minimumdeg;
18261     startingsize = 4;
18262 
18263     CHECKRANGE(maxnv,"n",3,MAXN);
18264     CHECKRANGE(minconnec,"-c",1,3);
18265     CHECKRANGE(minimumdeg,"-m",1,3);
18266 
18267     INCOMPAT(edgebound[0]>=0,"without -p","-e");
18268     INCOMPAT(maxfacesize>=0,"without -p","-f");
18269     INCOMPAT(minconnec == 3 && xswitch && minimumdeg == 3,"-c3","-x");
18270     INCOMPAT(Aswitch && (minimumdeg < 3 || minconnec < 3),
18271               "-A","-c1/2 or -m1/2");
18272 
18273     if (minconnec < 3 && maxnv > 8*sizeof(long))
18274     {
18275         fprintf(stderr,">E %s: connectivity < 3 is restricted to n < %d\n",
18276                    cmdname,(int)(8*sizeof(long)));
18277         exit(1);
18278     }
18279 
18280     if (dswitch) strcpy(outtypename,"cubic graphs");
18281     else         strcpy(outtypename,"triangulations");
18282 
18283     open_output_file();
18284 
18285     needgroup = Gswitch || minconnec < 3;
18286 
18287     hint = (maxnv < 18 ? 15 : 16);
18288     initialize_splitting(startingsize,hint,maxnv-1);
18289     if (splitlevel == 0 && res > 0) return;
18290 
18291     xconnec = minconnec;
18292 
18293     if (maxnv >= startingsize)
18294     {
18295         initialize_triang();
18296         canon(degree,numbering,&nbtot,&nbop);
18297 
18298 #ifdef FAST_FILTER_SIMPLE
18299 	if (FAST_FILTER_SIMPLE)
18300 #endif
18301         scansimple(nbtot,nbop);
18302     }
18303     else if (maxnv == 3 && !Aswitch)
18304     {
18305 	if (minconnec <= 2 && minimumdeg <= 2)
18306 	{
18307 	    make_cycle(3);
18308 	    canon(degree,numbering,&nbtot,&nbop);
18309 #ifdef FAST_FILTER_SIMPLE
18310 	if (FAST_FILTER_SIMPLE)
18311 #endif
18312 	    got_one(nbtot,nbop,2);
18313 	}
18314 	if (minconnec == 1 && minimumdeg == 1 && !Aswitch)
18315         {
18316             make_gyro();
18317 	    def[0] = nv - degree[0];
18318 	    def[1] = nv - degree[1];
18319 	    def[2] = nv - degree[2];
18320             canon(def,numbering,&nbtot,&nbop);
18321 #ifdef FAST_FILTER_SIMPLE
18322 	if (FAST_FILTER_SIMPLE)
18323 #endif
18324             got_one(nbtot,nbop,1);
18325         }
18326     }
18327 
18328 #ifdef STATS
18329     fprintf(msgfile,"Counts by min degree: ");
18330     for (i = minimumdeg; i <= 5; ++i)
18331     {
18332         PRINTBIG(msgfile,nummindeg[i]);
18333         if (i != 5) fprintf(msgfile," ");
18334         else fprintf(msgfile,"\n");
18335     }
18336 #endif
18337 
18338     if (vswitch && minconnec < 3 && !xswitch)
18339     {
18340         fprintf(msgfile,"By connectivity: ");
18341         for (i = minconnec; i <= 3; ++i)
18342         {
18343             if (i > minconnec) fprintf(msgfile," ");
18344             PRINTBIG(msgfile,nout[i]);
18345             if (i == 3) fprintf(msgfile," (3-5)-conn");
18346 	    else        fprintf(msgfile," %d-conn",i);
18347             if (i < 3) fprintf(msgfile,";");
18348         }
18349         fprintf(msgfile,"\n");
18350 
18351 	if (oswitch)
18352 	{
18353             fprintf(msgfile,"By connectivity (O-P): ");
18354             for (i = minconnec; i <= 3; ++i)
18355             {
18356                 if (i > minconnec) fprintf(msgfile," ");
18357                 PRINTBIG(msgfile,nout_op[i]);
18358                 if (i == 3) fprintf(msgfile," (3-5)-conn");
18359 	        else        fprintf(msgfile," %d-conn",i);
18360                 if (i < 3) fprintf(msgfile,";");
18361             }
18362             fprintf(msgfile,"\n");
18363 	}
18364     }
18365 }
18366 
18367 /****************************************************************************/
18368 
18369 static void
polygon_dispatch(void)18370 polygon_dispatch(void)
18371 
18372 /* Triangulations of a polygon.  This works by making a triangulation
18373    one size bigger, then deleting a vertex.  maxnv is set one size
18374    larger to achieve this, but put back before this procedure returns. */
18375 {
18376     int i,startingsize,nbtot,nbop,hint;
18377 
18378 
18379     if (minconnec <= 0) minconnec = 3;
18380     if (minimumdeg <= 0) minimumdeg = 3;
18381     startingsize = 4;
18382 
18383     CHECKRANGE(maxnv,"n",startingsize-1,MAXN-1);
18384     ++maxnv;
18385     CHECKRANGE(minconnec,"-c",2,3);
18386     CHECKRANGE(minimumdeg,"-m",2,3);
18387     PERROR(polygonsize==1||polygonsize==2||polygonsize>=maxnv,
18388 	"value of -P must be empty or 3..n-1\n");
18389 
18390     INCOMPAT(Aswitch,"-P","-A");
18391     INCOMPAT(pswitch,"-P","-p");
18392     INCOMPAT(bswitch,"-P","-b");
18393     INCOMPAT(tswitch,"-P","-t");
18394     INCOMPAT(qswitch,"-P","-q");
18395     INCOMPAT(edgebound[0]>=0,"-P","-e");
18396     INCOMPAT(maxfacesize>=0,"-P","-f");
18397 
18398     if (minimumdeg < minconnec) minimumdeg = minconnec;
18399 
18400     if (dswitch) strcpy(outtypename,"duals of disk triangulations");
18401     else         strcpy(outtypename,"disk triangulations");
18402 
18403     open_output_file();
18404 
18405     for (i = 0; i <= MAXN; ++i) nout_p[i] = nout_p_op[i] = 0;
18406 
18407     needgroup = TRUE;
18408 
18409     hint = (maxnv < 18 ? 15 : 16);
18410     initialize_splitting(startingsize,hint,maxnv-1);
18411     if (splitlevel == 0 && res > 0)
18412     {
18413 	--maxnv;
18414 	return;
18415     }
18416 
18417     xconnec = minconnec;
18418 
18419     initialize_triang();
18420     canon(degree,numbering,&nbtot,&nbop);
18421     scansimple(nbtot,nbop);
18422 
18423     --maxnv;
18424 
18425     if (vswitch && polygonsize == 0)
18426     {
18427         for (i = 0; i <= MAXN; ++i)
18428         if (nout_p[i] > 0)
18429         {
18430             fprintf(msgfile," With %2d-gon: ",i);
18431             if (oswitch)
18432             {
18433                 PRINTBIG(msgfile,nout_p_op[i]);
18434                 fprintf(msgfile," (");
18435                 PRINTBIG(msgfile,nout_p[i]);
18436                 fprintf(msgfile," classes)\n");
18437             }
18438             else
18439             {
18440                 PRINTBIG(msgfile,nout_p[i]);
18441                 fprintf(msgfile,"\n");
18442             }
18443         }
18444     }
18445 }
18446 
18447 /****************************************************************************/
18448 
18449 static void
min4_dispatch(void)18450 min4_dispatch(void)
18451 
18452 /* Case of minimum degree >= 4, except for polygons and polytopes. */
18453 {
18454     int startingsize,nbtot,nbop,hint;
18455     triangle nft[MAXN];
18456 
18457     if (minimumdeg <= 0) minimumdeg = 4;
18458     if (minconnec <= 0) minconnec = 3;
18459     startingsize = 6;
18460 
18461     CHECKRANGE(maxnv,"n",startingsize,MAXN);
18462     CHECKRANGE(minconnec,"-c",3,4);
18463     CHECKRANGE(minimumdeg,"-m",4,4);
18464 
18465     INCOMPAT(tswitch,"-m4 or -c4","-t");
18466     INCOMPAT(qswitch,"-m4 or -c4","-q");
18467     INCOMPAT(Aswitch,"-m4 or -c4","-A");
18468     INCOMPAT(edgebound[0]>=0,"-m4 without -p","-e");
18469     INCOMPAT(maxfacesize>=0,"-m4 without -p","-f");
18470     INCOMPAT(minconnec==4&&xswitch,"-c4","-x");
18471 
18472     if (dswitch) strcpy(outtypename,"cubic graphs");
18473     else         strcpy(outtypename,"triangulations");
18474 
18475     open_output_file();
18476 
18477     needgroup = Gswitch;
18478     if (minconnec == 4) xswitch = TRUE;
18479 
18480     xconnec = minconnec;
18481 
18482     hint = (maxnv < 24 ? 18 : 19);
18483     initialize_splitting(startingsize,hint,maxnv-3);
18484     if (splitlevel == 0 && res > 0) return;
18485 
18486     initialize_min4();
18487     canon(degree,numbering,&nbtot,&nbop);
18488 
18489 #ifdef FAST_FILTER_MIN4
18490     if (FAST_FILTER_MIN4)
18491 #endif
18492     {
18493         if (xswitch || minconnec == 4)
18494 	    scanmin4c(nbtot,nbop,splitlevel==6,NULL,nft,0);
18495         else
18496 	    scanmin4(nbtot,nbop,splitlevel==6,NULL);
18497     }
18498 }
18499 
18500 /****************************************************************************/
18501 
18502 static void
min5_dispatch(void)18503 min5_dispatch(void)
18504 
18505 /* Case of minimum degree == 5, except for polygons and polytopes. */
18506 {
18507     int i,startingsize,nbtot,nbop,hint,nbangles;
18508     EDGE *prevA[MAXN],*bangle[MAXE/2];
18509 
18510     if (minimumdeg <= 0) minimumdeg = 5;
18511     if (minconnec <= 0) minconnec = 3;
18512     startingsize = 12;
18513 
18514     CHECKRANGE(maxnv,"n",startingsize,MAXN);
18515     CHECKRANGE(minconnec,"-c",3,5);
18516     CHECKRANGE(minimumdeg,"-m",5,5);
18517 
18518     INCOMPAT(tswitch,"-m5 or -c5","-t");
18519     INCOMPAT(qswitch,"-m5 or -c5","-q");
18520     INCOMPAT(Aswitch,"-m5 or -c5","-A");
18521     INCOMPAT(edgebound[0]>=0,"-m5 without -p","-e");
18522     INCOMPAT(maxfacesize>=0,"-m5 without -p","-f");
18523     INCOMPAT(minconnec==5&&xswitch,"-c5","-x");
18524 
18525     if (dswitch) strcpy(outtypename,"cubic graphs");
18526     else         strcpy(outtypename,"triangulations");
18527 
18528     open_output_file();
18529 
18530     needgroup = Gswitch;
18531 
18532     hint = (maxnv < 35 ? 28 : maxnv < 38 ? 29 : 30);
18533     initialize_splitting(startingsize,hint,maxnv-5);
18534     if (splitlevel == 0 && res > 0) return;
18535 
18536     xconnec = minconnec;
18537 
18538     initialize_min5();
18539     canon(degree,numbering,&nbtot,&nbop);
18540 
18541     if (minconnec < 5)
18542     {
18543         all_5_bangles(bangle,&nbangles);
18544 #ifdef FAST_FILTER_MIN5
18545         if (FAST_FILTER_MIN5)
18546 #endif
18547         scanmin5(nbtot,nbop,splitlevel==12,prevA,0,bangle,nbangles);
18548         if (vswitch && !xswitch)
18549         {
18550             fprintf(msgfile,"By connectivity: ");
18551             for (i = minconnec; i <= 5; ++i)
18552             {
18553                 if (i > minconnec) fprintf(msgfile," ");
18554                 PRINTBIG(msgfile,nout[i]);
18555 	        fprintf(msgfile," %d-conn",i);
18556                 if (i < 5) fprintf(msgfile,";");
18557             }
18558             fprintf(msgfile,"\n");
18559 
18560 	    if (oswitch)
18561 	    {
18562                 fprintf(msgfile,"By connectivity (O-P): ");
18563                 for (i = minconnec; i <= 5; ++i)
18564                 {
18565                     if (i > minconnec) fprintf(msgfile," ");
18566                     PRINTBIG(msgfile,nout_op[i]);
18567 	            fprintf(msgfile," %d-conn",i);
18568                     if (i < 5) fprintf(msgfile,";");
18569                 }
18570                 fprintf(msgfile,"\n");
18571 	    }
18572         }
18573     }
18574     else
18575 #ifdef FAST_FILTER_MIN5
18576         if (FAST_FILTER_MIN5)
18577 #endif
18578         scanmin5c(nbtot,nbop,splitlevel==12,prevA,0);
18579 }
18580 
18581 /****************************************************************************/
18582 
18583 static void
polytope_dispatch(void)18584 polytope_dispatch(void)
18585 
18586 /* Polytopes.  Main options are -m4, -m5 and neither. */
18587 {
18588     int startingsize,nbtot,nbop,i,hint,nbangles,maxundir;
18589     EDGE *prevA[MAXN],*bangle[MAXE/2];
18590 
18591   /* Polytopes are made by first making 3-connected triangulations,
18592      then deleting edges in a second phase.  minconn and minimumdeg
18593      are used in the first phase; minpolyconn and minpolydeg in the
18594      second phase.  Since simple triangulations are 3-connected and
18595      have minimum degree at least 3, minconn and minimumdeg are at
18596      least 3.  However, minpolyconn and minpolydeg can be anything
18597      from 1 to minconn and minimumdeg. */
18598 
18599     if (minconnec <= 0) minconnec = 3;
18600     if (minconnec < 3)
18601     {
18602 	minpolyconnec = minconnec;
18603 	minconnec = 3;
18604     }
18605     else
18606 	minpolyconnec = minconnec;
18607 
18608     if (minimumdeg <= 0)
18609     {
18610 	minimumdeg = minconnec;
18611 	minpolydeg = minpolyconnec;
18612     }
18613     else
18614     {
18615 	minpolydeg = minimumdeg;
18616 	minimumdeg = MAX(minimumdeg,3);
18617     }
18618 
18619     if (minconnec > minimumdeg) minimumdeg = minconnec;
18620     if (minpolyconnec > minpolydeg) minpolydeg = minpolyconnec;
18621 
18622     startingsize = (minimumdeg == 4 ? 6 : (minimumdeg == 5 ? 12 : 4));
18623 
18624     CHECKRANGE(maxnv,"n",2,MAXN);
18625     CHECKRANGE(maxnv,"n",2,64);
18626     CHECKRANGE(minpolyconnec,"-c",1,3);
18627     CHECKRANGE(minpolydeg,"-m",1,5);
18628 
18629     INCOMPAT(polygonsize>=0,"-p","-P");
18630     INCOMPAT(bswitch,"-p","-b");
18631     INCOMPAT(qswitch,"-p","-q");
18632     INCOMPAT(tswitch,"-p","-t");
18633     INCOMPAT(Aswitch,"-p","-A");
18634 /* INCOMPAT(minconnec == 3 && xswitch,"-c3","-x");  changed 19/2/08 */
18635     INCOMPAT(minpolyconnec == 3 && xswitch,"-c3","-x");
18636 
18637     maxundir = (maxnv == 2 ? 1 : 3*maxnv-6);
18638     if (edgebound[0] < 0) edgebound[0] = 0;
18639     if (edgebound[1] < 0) edgebound[1] = maxundir;
18640     if (edgebound[1] > maxundir) edgebound[1] = maxundir;
18641     if (maxfacesize <= 0) maxfacesize = MAXE;
18642 
18643     CHECKRANGE(edgebound[0],"-e",0,maxundir);
18644     CHECKRANGE(edgebound[1],"-e",0,maxundir);
18645     PERROR(edgebound[0] > edgebound[1],
18646 	   "The first value of -e can't be greater than the second");
18647     PERROR(maxnv*minpolydeg > 2*edgebound[1],
18648 	   "The upper bound for -e is impossibly low");
18649     CHECKRANGE(maxfacesize,"-f",3,MAXE);
18650 
18651     xconnec = minpolyconnec;
18652 
18653     if (maxnv >= 4 && (edgebound[0] == maxundir || maxfacesize == 3))
18654     {
18655 	pswitch = FALSE;
18656 	edgebound[0] = edgebound[1] = maxfacesize = -1;
18657         if      (minimumdeg == 4) min4_dispatch();
18658 	else if (minimumdeg == 5) min5_dispatch();
18659         else                      simple_dispatch();
18660 	return;
18661     }
18662 
18663     edgebound[0] *= 2;
18664     edgebound[1] *= 2;
18665 
18666     strcpy(outtypename,"polytopes");
18667 
18668     open_output_file();
18669 
18670     for (i = 0; i <= maxundir; ++i)
18671     {
18672 	nout_e[i] = nout_e_op[i] = 0;
18673 #ifdef STATS
18674 	numrooted_e[i] = 0;
18675 #endif
18676     }
18677 
18678     needgroup = TRUE;
18679 
18680     if (minimumdeg == 5)
18681     {
18682 	hint = 29;
18683 	initialize_splitting(startingsize,hint,maxnv-5);
18684         if (splitlevel == 0 && res > 0) return;
18685         initialize_min5();
18686         canon(degree,numbering,&nbtot,&nbop);
18687         all_5_bangles(bangle,&nbangles);
18688         scanmin5(nbtot,nbop,splitlevel==12,prevA,0,bangle,nbangles);
18689     }
18690     else if (minimumdeg == 4)
18691     {
18692 	hint = (maxnv < 22 ? 18 : 19);
18693 	initialize_splitting(startingsize,hint,maxnv-3);
18694         if (splitlevel == 0 && res > 0) return;
18695         initialize_min4();
18696         canon(degree,numbering,&nbtot,&nbop);
18697         scanmin4(nbtot,nbop,splitlevel==6,NULL);
18698     }
18699     else if (maxnv >= 4)
18700     {
18701         hint = (maxnv < 17 ? 15 : 16);
18702 	initialize_splitting(startingsize,hint,maxnv-1);
18703         if (splitlevel == 0 && res > 0) return;
18704 	initialize_triang();
18705 	canon(degree,numbering,&nbtot,&nbop);
18706 	scansimple(nbtot,nbop);
18707     }
18708     else
18709     {
18710         if (maxnv <= 3 && minpolydeg == 1  && minpolyconnec == 1
18711                             && edgebound[0] <= 2*maxnv-2
18712                             && edgebound[1] >= 2*maxnv-2
18713                             && maxfacesize >= 2*maxnv-2)
18714         {
18715             make_me_a_star(maxnv);
18716             canon(degree,numbering,&nbtot,&nbop);
18717             xconnec = minconnec;
18718             got_one(nbtot,nbop,1);
18719         }
18720         if (maxnv == 3 && minpolydeg <= 2 && minpolyconnec <= 2
18721                             && edgebound[0] <= 6
18722                             && edgebound[1] >= 6)
18723         {
18724             make_cycle(maxnv);
18725             canon(degree,numbering,&nbtot,&nbop);
18726             xconnec = minconnec;
18727             got_one(nbtot,nbop,2);
18728         }
18729     }
18730 
18731     if (vswitch)
18732     {
18733         for (i = 0; i <= maxundir; ++i)
18734         if (nout_e[i] > 0)
18735         {
18736             fprintf(msgfile," With %2d edges and %2d faces: ",i,2+i-maxnv);
18737 	    if (oswitch)
18738 	    {
18739 		PRINTBIG(msgfile,nout_e_op[i]);
18740 		fprintf(msgfile," (");
18741                 PRINTBIG(msgfile,nout_e[i]);
18742 		fprintf(msgfile," classes)");
18743 #ifdef STATS
18744 		fprintf(msgfile," ");
18745 		PRINTBIG(msgfile,numrooted_e[i]);
18746 		fprintf(msgfile," rooted");
18747 #endif
18748 		fprintf(msgfile,"\n");
18749 	    }
18750 	    else
18751 	    {
18752                 PRINTBIG(msgfile,nout_e[i]);
18753 	        fprintf(msgfile,"\n");
18754 	    }
18755         }
18756         if (!xswitch && minpolyconnec < 3)
18757         {
18758             fprintf(msgfile,"By connectivity: ");
18759             for (i = minpolyconnec; i <= 3; ++i)
18760             {
18761                 if (i > minpolyconnec) fprintf(msgfile," ");
18762                 PRINTBIG(msgfile,nout[i]);
18763                 if (i == 3) fprintf(msgfile," (3-5)-conn");
18764 	        else        fprintf(msgfile," %d-conn",i);
18765                 if (i < 3) fprintf(msgfile,";");
18766             }
18767             fprintf(msgfile,"\n");
18768 
18769 	    if (oswitch)
18770 	    {
18771                 fprintf(msgfile,"By connectivity (O-P): ");
18772                 for (i = minpolyconnec; i <= 3; ++i)
18773                 {
18774                     if (i > minpolyconnec) fprintf(msgfile," ");
18775                     PRINTBIG(msgfile,nout_op[i]);
18776                     if (i == 3) fprintf(msgfile," (3-5)-conn");
18777 	            else        fprintf(msgfile," %d-conn",i);
18778                     if (i < 3) fprintf(msgfile,";");
18779                 }
18780                 fprintf(msgfile,"\n");
18781 	    }
18782 	}
18783     }
18784 }
18785 
18786 /****************************************************************************/
18787 
18788 static void
polytope_c4_dispatch(void)18789 polytope_c4_dispatch(void)
18790 
18791 /* 4-connected polytopes. */
18792 {
18793     int startingsize,nbtot,nbop,i,hint,nbangles,maxundir;
18794     EDGE *prevA[MAXN],*bangle[MAXE/2];
18795     triangle nft[MAXN];
18796 
18797   /* Polytopes are made by first making 4-connected triangulations,
18798      then deleting edges in a second phase.  minconn and minimumdeg
18799      are used in the first phase; minpolyconn and minpolydeg in the
18800      second phase. */
18801 
18802     minpolyconnec = minconnec;
18803 
18804     if (minimumdeg <= 0)
18805     {
18806 	minimumdeg = minconnec;
18807 	minpolydeg = minpolyconnec;
18808     }
18809     else
18810     {
18811 	minpolydeg = minimumdeg;
18812 	minimumdeg = MAX(minimumdeg,4);
18813     }
18814 
18815     if (minconnec > minimumdeg) minimumdeg = minconnec;
18816     if (minpolyconnec > minpolydeg) minpolydeg = minpolyconnec;
18817 
18818     CHECKRANGE(minpolyconnec,"-c",4,4);
18819     CHECKRANGE(minpolydeg,"-m",4,5);
18820 
18821     INCOMPAT(polygonsize>=0,"-p","-P");
18822     INCOMPAT(bswitch,"-p","-b");
18823     INCOMPAT(qswitch,"-p","-q");
18824     INCOMPAT(tswitch,"-p","-t");
18825     INCOMPAT(Aswitch,"-p","-A");
18826     INCOMPAT(xswitch,"-pc4","-x");
18827 
18828     maxundir = (maxnv == 2 ? 1 : 3*maxnv-6);
18829     if (edgebound[0] < 0) edgebound[0] = 0;
18830     if (edgebound[1] < 0) edgebound[1] = maxundir;
18831     if (edgebound[1] > maxundir) edgebound[1] = maxundir;
18832     if (maxfacesize <= 0) maxfacesize = MAXE;
18833 
18834     CHECKRANGE(edgebound[0],"-e",0,maxundir);
18835     CHECKRANGE(edgebound[1],"-e",0,maxundir);
18836     PERROR(edgebound[0] > edgebound[1],
18837 	   "The first value of -e can't be greater than the second");
18838     PERROR(maxnv*minpolydeg > 2*edgebound[1],
18839 	   "The upper bound for -e is impossibly low");
18840     CHECKRANGE(maxfacesize,"-f",3,MAXE);
18841 
18842     xconnec = minpolyconnec;
18843 
18844     edgebound[0] *= 2;
18845     edgebound[1] *= 2;
18846 
18847     strcpy(outtypename,"polytopes");
18848 
18849     open_output_file();
18850 
18851     for (i = 0; i <= maxundir; ++i)
18852     {
18853 	nout_e[i] = nout_e_op[i] = 0;
18854 #ifdef STATS
18855 	numrooted_e[i] = 0;
18856 #endif
18857     }
18858 
18859     needgroup = TRUE;
18860 
18861     if (minimumdeg == 5)
18862     {
18863         startingsize = 12;
18864         CHECKRANGE(maxnv,"n",startingsize,MAXN);
18865         CHECKRANGE(maxnv,"n",startingsize,8*(int)sizeof(unsigned long));
18866 
18867         hint = (maxnv < 35 ? 28 : maxnv < 38 ? 29 : 30);
18868 
18869 	initialize_splitting(startingsize,hint,maxnv-5);
18870         if (splitlevel == 0 && res > 0) return;
18871         initialize_min5();
18872         canon(degree,numbering,&nbtot,&nbop);
18873         all_5_bangles(bangle,&nbangles);
18874         scanmin5(nbtot,nbop,splitlevel==12,prevA,0,bangle,nbangles);
18875     }
18876     else /* minimumdeg == 4 */
18877     {
18878 	startingsize = 6;
18879         CHECKRANGE(maxnv,"n",startingsize,MAXN);
18880         CHECKRANGE(maxnv,"n",startingsize,8*(int)sizeof(unsigned long));
18881 
18882 	hint = (maxnv < 22 ? 18 : 19);
18883 	initialize_splitting(startingsize,hint,maxnv-3);
18884         if (splitlevel == 0 && res > 0) return;
18885         initialize_min4();
18886         canon(degree,numbering,&nbtot,&nbop);
18887         scanmin4c(nbtot,nbop,splitlevel==6,NULL,nft,0);
18888     }
18889 
18890     if (vswitch)
18891     {
18892         for (i = 0; i <= maxundir; ++i)
18893         if (nout_e[i] > 0)
18894         {
18895             fprintf(msgfile," With %2d edges and %2d faces: ",i,2+i-maxnv);
18896 	    if (oswitch)
18897 	    {
18898 		PRINTBIG(msgfile,nout_e_op[i]);
18899 		fprintf(msgfile," (");
18900                 PRINTBIG(msgfile,nout_e[i]);
18901 		fprintf(msgfile," classes)");
18902 #ifdef STATS
18903 		fprintf(msgfile," ");
18904 		PRINTBIG(msgfile,numrooted_e[i]);
18905 		fprintf(msgfile," rooted");
18906 #endif
18907 		fprintf(msgfile,"\n");
18908 	    }
18909 	    else
18910 	    {
18911                 PRINTBIG(msgfile,nout_e[i]);
18912 	        fprintf(msgfile,"\n");
18913 	    }
18914         }
18915     }
18916 }
18917 
18918 /****************************************************************************/
18919 
18920 static void
eulerian_dispatch(void)18921 eulerian_dispatch(void)
18922 
18923 /* Eulerian triangulations. */
18924 {
18925     int startingsize,nbtot,nbop,hint;
18926     EDGE *Pedges[MAXN/2+1];
18927     triangle nft[MAXN];
18928 
18929     if (minimumdeg <= 0) minimumdeg = 4;
18930     if (minconnec <= 0) minconnec = 3;
18931     startingsize = 6;
18932 
18933     CHECKRANGE(maxnv,"n",startingsize,MAXN);
18934     CHECKRANGE(minconnec,"-c",3,4);
18935     CHECKRANGE(minimumdeg,"-m",4,4);
18936 
18937     INCOMPAT(pswitch,"-b","-p");
18938     INCOMPAT(qswitch,"-b","-q");
18939     INCOMPAT(Aswitch,"-b","-A");
18940     INCOMPAT(polygonsize>=0,"-b","-P");
18941     INCOMPAT(tswitch,"-b","-t");
18942     INCOMPAT(edgebound[0]>=0,"-b","-e");
18943     INCOMPAT(maxfacesize>=0,"-b","-f");
18944 
18945     if (dswitch) strcpy(outtypename,"bipartite cubic graphs");
18946     else         strcpy(outtypename,"eulerian triangulations");
18947 
18948     open_output_file();
18949 
18950     needgroup = Gswitch;
18951 
18952     hint = (maxnv < 30 ? 23 : 24);
18953     initialize_splitting(startingsize,hint,maxnv-2);
18954     if (splitlevel == 0 && res > 0) return;
18955 
18956     initialize_bip();
18957     xconnec = minconnec;
18958     canon(degree,numbering,&nbtot,&nbop);
18959 #ifdef FAST_FILTER_BIP
18960     if (FAST_FILTER_BIP)
18961 #endif
18962     {
18963         if (xswitch || minconnec == 4)
18964             scanbipartite4c(nbtot,nbop,firstedge[0],splitlevel==6,Pedges,0,nft,0);
18965         else
18966             scanbipartite(nbtot,nbop,firstedge[0],splitlevel==6,Pedges,0);
18967     }
18968 }
18969 
18970 /****************************************************************************/
18971 
18972 static void
quadrangulation_dispatch(void)18973 quadrangulation_dispatch(void)
18974 
18975 /* Simple quadrangulations. */
18976 {
18977     int startingsize,nbtot,nbop,hint;
18978     EDGE *P1edges[MAXN];
18979 
18980     if (minimumdeg <= 0) minimumdeg = 3;
18981     if (minconnec <= 0) minconnec = 3;
18982     if (minimumdeg==2 && minconnec>=3) minimumdeg = 3;
18983     startingsize = (minimumdeg == 2 ? 4 : 8);
18984 
18985     CHECKRANGE(maxnv,"n",startingsize,MAXN);
18986     CHECKRANGE(minconnec,"-c",2,4);
18987     CHECKRANGE(minimumdeg,"-m",2,3);
18988 
18989     INCOMPAT(pswitch,"-q","-p");
18990     INCOMPAT(bswitch,"-q","-b");
18991     INCOMPAT(Aswitch,"-q","-A");
18992     INCOMPAT(polygonsize>=0,"-q","-P");
18993     INCOMPAT(tswitch,"-q","-t");
18994     INCOMPAT(edgebound[0]>=0,"-q","-e");
18995     INCOMPAT(maxfacesize>=0,"-q","-f");
18996 
18997     if (dswitch) strcpy(outtypename,"quartic graphs");
18998     else         strcpy(outtypename,"quadrangulations");
18999 
19000     open_output_file();
19001 
19002     needgroup = Gswitch;
19003 
19004     if (minimumdeg == 2)
19005     {
19006         hint = (maxnv < 25 ? 18 : 19);
19007         initialize_splitting(startingsize,hint,maxnv-1);
19008         if (splitlevel == 0 && res > 0) return;
19009         initialize_quadrangulations();
19010 	extend_quadr_P0(firstedge[1]);   /* make square */
19011         xconnec = minconnec;
19012         canon(degree,numbering,&nbtot,&nbop);
19013 	scanquadrangulations_all(nbtot,nbop);
19014 #ifdef STATS
19015         fprintf(msgfile,"Counts by min degree: ");
19016         PRINTBIG(msgfile,nummindeg[2]);
19017         fprintf(msgfile," ");
19018         PRINTBIG(msgfile,nummindeg[3]);
19019         fprintf(msgfile,"\n");
19020 #endif
19021     }
19022     else
19023     {
19024         hint = (maxnv < 33 ? 24 : 25);
19025         initialize_splitting(startingsize,hint,maxnv-2);
19026         if (splitlevel == 0 && res > 0) return;
19027         initialize_min3_quadrangulations();
19028         xconnec = minconnec;
19029         canon(degree,numbering,&nbtot,&nbop);
19030         if (minconnec == 3)
19031             scanquadrangulations(nbtot,nbop,firstedge[0],
19032 						splitlevel==8,P1edges,0);
19033         else if (minconnec == 4)
19034             scanquadrangulations_nf4(nbtot,nbop,firstedge[0],
19035 					        splitlevel==8,P1edges,0);
19036         else
19037             scanquadrangulations_min3(nbtot,nbop,firstedge[0],
19038 					        splitlevel==8,P1edges,0);
19039     }
19040 }
19041 
19042 /****************************************************************************/
19043 
19044 static void
bipartite_dispatch(void)19045 bipartite_dispatch(void)
19046 
19047 /* General bipartite graphs.  Main options are -m# -c# for #=1,2,3.  */
19048 {
19049     int startingsize,nbtot,nbop,i,hint,maxundir;
19050     EDGE *P1edges[MAXN];
19051 
19052   /* Bipartite graphs are made by first making quadrangulations,
19053      then deleting edges in a second phase.  minconn and minimumdeg
19054      are used in the first phase; minpolyconn and minpolydeg in the
19055      second phase. */
19056 
19057     if (minconnec <= 0) minconnec = 3;
19058     if (minconnec < 3)
19059     {
19060 	minpolyconnec = minconnec;
19061 	minconnec = 2;
19062     }
19063     else
19064 	minpolyconnec = minconnec;
19065 
19066     if (minimumdeg <= 0)
19067     {
19068 	minimumdeg = minconnec;
19069 	minpolydeg = minpolyconnec;
19070     }
19071     else
19072     {
19073 	minpolydeg = minimumdeg;
19074 	minimumdeg = MAX(minimumdeg,2);
19075     }
19076 
19077     if (minconnec > minimumdeg) minimumdeg = minconnec;
19078     if (minpolyconnec > minpolydeg) minpolydeg = minpolyconnec;
19079 
19080     startingsize = (minimumdeg == 2 ? 4 : 8);
19081 
19082     CHECKRANGE(maxnv,"n",(minpolydeg==1?2:startingsize),MAXN);
19083     CHECKRANGE(maxnv,"n",2,64);
19084     CHECKRANGE(minpolyconnec,"-c",1,3);
19085     CHECKRANGE(minpolydeg,"-m",1,3);
19086 
19087     INCOMPAT(polygonsize>=0,"-pb","-P");
19088     INCOMPAT(qswitch,"-pb","-q");
19089     INCOMPAT(tswitch,"-pb","-t");
19090     INCOMPAT(Aswitch,"-pb","-A");
19091     INCOMPAT(minpolyconnec == 3 && xswitch,"-c3","-x");
19092 
19093     maxundir = (maxnv == 2 ? 1 : 2*maxnv-4);
19094     if (edgebound[0] < 0) edgebound[0] = 0;
19095     if (edgebound[1] < 0) edgebound[1] = maxundir;
19096     if (edgebound[1] > 2*maxnv-4) edgebound[1] = maxundir;
19097     if (maxfacesize <= 0) maxfacesize = MAXE;
19098     maxfacesize &= ~1;  /* Must be even */
19099 
19100     CHECKRANGE(edgebound[0],"-e",0,maxundir);
19101     CHECKRANGE(edgebound[1],"-e",0,maxundir);
19102     PERROR(edgebound[0] > edgebound[1],
19103 	   "The first value of -e can't be greater than the second");
19104     CHECKRANGE(maxfacesize,"-f",4,MAXE);
19105 
19106     xconnec = minpolyconnec;
19107 
19108     if (maxnv >= startingsize &&
19109                (edgebound[0] == maxundir || maxfacesize == 4))
19110     {
19111 	pswitch = bswitch = FALSE;
19112 	edgebound[0] = edgebound[1] = maxfacesize = -1;
19113         quadrangulation_dispatch();
19114 	return;
19115     }
19116 
19117     edgebound[0] *= 2;
19118     edgebound[1] *= 2;
19119 
19120     if (dswitch) strcpy(outtypename,"eulerian graphs");
19121     else         strcpy(outtypename,"bipartite graphs");
19122 
19123     open_output_file();
19124 
19125     for (i = 0; i <= maxundir; ++i) nout_e[i] = nout_e_op[i] = 0;
19126 
19127     needgroup = TRUE;
19128 
19129     if (minimumdeg == 2)
19130     {
19131 	hint = (maxnv < 26 ? 18 : 19);
19132         initialize_splitting(startingsize,hint,maxnv-1);
19133         if (splitlevel == 0 && res > 0) return;
19134 	if (maxnv >= 4)
19135 	{
19136             initialize_quadrangulations();
19137             extend_quadr_P0(firstedge[1]);   /* make square */
19138             xconnec = minconnec;
19139             canon(degree,numbering,&nbtot,&nbop);
19140 #ifdef FAST_FILTER_QUAD
19141 	    if (FAST_FILTER_QUAD)
19142 #endif
19143             scanquadrangulations_all(nbtot,nbop);
19144 	}
19145 	if (minpolydeg == 1 && edgebound[0] <= 2*maxnv-2
19146 		            && edgebound[1] >= 2*maxnv-2
19147                             && maxfacesize >= 2*maxnv-2
19148 			    && res == 0)
19149 	{
19150 	    make_me_a_star(maxnv);
19151 	    canon(degree,numbering,&nbtot,&nbop);
19152             xconnec = minconnec;
19153 #ifdef FAST_FILTER_QUAD
19154 	    if (FAST_FILTER_QUAD)
19155 #endif
19156 	    got_one(nbtot,nbop,1);
19157 	}
19158     }
19159     else
19160     {
19161 	hint = (maxnv < 31 ? 25 : 26);
19162         initialize_splitting(startingsize,hint,maxnv-2);
19163         if (splitlevel == 0 && res > 0) return;
19164         initialize_min3_quadrangulations();
19165         xconnec = minconnec;
19166         canon(degree,numbering,&nbtot,&nbop);
19167 #ifdef FAST_FILTER_QUAD
19168 	if (FAST_FILTER_QUAD)
19169 #endif
19170 	{
19171             if (minconnec == 3)
19172                 scanquadrangulations(nbtot,nbop,firstedge[0],
19173                                                 splitlevel==8,P1edges,0);
19174             else
19175                 scanquadrangulations_min3(nbtot,nbop,firstedge[0],
19176                                                 splitlevel==8,P1edges,0);
19177 	}
19178     }
19179 
19180     if (vswitch)
19181     {
19182         for (i = 0; i <= maxundir; ++i)
19183         if (nout_e[i] > 0)
19184         {
19185             fprintf(msgfile," With %2d edges and %2d faces: ",i,2+i-maxnv);
19186 	    if (oswitch)
19187 	    {
19188 		PRINTBIG(msgfile,nout_e_op[i]);
19189 		fprintf(msgfile," (");
19190                 PRINTBIG(msgfile,nout_e[i]);
19191 		fprintf(msgfile," classes)");
19192 #ifdef STATS
19193 		fprintf(msgfile," ");
19194 		PRINTBIG(msgfile,numrooted_e[i]);
19195 		fprintf(msgfile," rooted");
19196 #endif
19197 		fprintf(msgfile,"\n");
19198 	    }
19199 	    else
19200 	    {
19201                 PRINTBIG(msgfile,nout_e[i]);
19202 	        fprintf(msgfile,"\n");
19203 	    }
19204         }
19205         if (!xswitch && minpolyconnec < 3)
19206         {
19207             fprintf(msgfile,"By connectivity: ");
19208             for (i = minpolyconnec; i <= 3; ++i)
19209             {
19210                 if (i > minpolyconnec) fprintf(msgfile," ");
19211                 PRINTBIG(msgfile,nout[i]);
19212                 if (i == 3) fprintf(msgfile," (3-5)-conn");
19213 	        else        fprintf(msgfile," %d-conn",i);
19214                 if (i < 3) fprintf(msgfile,";");
19215             }
19216             fprintf(msgfile,"\n");
19217 
19218 	    if (oswitch)
19219 	    {
19220                 fprintf(msgfile,"By connectivity (O-P): ");
19221                 for (i = minpolyconnec; i <= 3; ++i)
19222                 {
19223                     if (i > minpolyconnec) fprintf(msgfile," ");
19224                     PRINTBIG(msgfile,nout_op[i]);
19225                     if (i == 3) fprintf(msgfile," (3-5)-conn");
19226 	            else        fprintf(msgfile," %d-conn",i);
19227                     if (i < 3) fprintf(msgfile,";");
19228                 }
19229                 fprintf(msgfile,"\n");
19230 	    }
19231 	}
19232     }
19233 }
19234 
19235 /****************************************************************************/
19236 
19237 static void
unused_functions(void)19238 unused_functions(void)
19239 
19240 /* Don't call this, it is just to avoid warning messages about
19241  * functions defined but not used. */
19242 {
19243     (void) maxdegree();
19244     (void) non_facial_triangles();
19245     (void) has_non_facial_triangle();
19246     (void) numedgeorbits(0,0);
19247     (void) numfaceorbits(0,0);
19248     (void) numopfaceorbits(0,0);
19249     (void) numorbits(0,0);
19250     (void) numoporbits(0,0);
19251     (void) numorbitsonface(0,0,NULL);
19252     (void) make_dual();
19253     (void) show_group(NULL,0,0);
19254     (void) connectivity();
19255     check_it(0,0);
19256     check_am2(0);
19257 
19258     unused_functions();
19259 }
19260 
19261 /****************************************************************************/
19262 
19263 int
main(int argc,char * argv[])19264 main(int argc, char *argv[])
19265 {
19266     int i;
19267 #if CPUTIME
19268     struct tms timestruct0,timestruct1;
19269 
19270     times(&timestruct0);
19271 #endif
19272 
19273     if (argc > 1
19274         && (strcmp(argv[1],"-help") == 0 || (strcmp(argv[1],"--help") == 0)))
19275     {
19276 	fprintf(stderr,"Plantri version %s\n",VERSION);
19277 	fprintf(stderr,
19278             "Usage: %s %s n [res/mod] [outfile]\n",argv[0],SWITCHES);
19279 #ifdef HELPMESSAGE
19280 	HELPMESSAGE;
19281 #endif
19282         fprintf(stderr,"See plantri-guide.txt for more information.\n");
19283 	return 0;
19284     }
19285 
19286     decode_command_line(argc,argv);
19287 
19288 #ifdef SPLITTEST
19289     if (mod == 1) mod = 2;
19290     uswitch = TRUE;
19291     aswitch = gswitch = sswitch = Eswitch = FALSE;
19292 #endif
19293 
19294     if (minconnec < 0 && (tswitch || xswitch))
19295     {
19296 	fprintf(stderr,
19297 	 ">E %s: -t and -x can only be used in conjunction with -c\n",cmdname);
19298 	exit(1);
19299     }
19300 
19301     for (i = 0; i < 6; ++i) nout[i] = nout_op[i] = 0;
19302     nout_V = 0;
19303 
19304 #ifdef STATS
19305     ntriv = numrooted = 0;
19306     nummindeg[1] = 0;
19307     nummindeg[2] = 0;
19308     nummindeg[3] = 0;
19309     nummindeg[4] = 0;
19310     nummindeg[5] = 0;
19311 #endif
19312 
19313 #ifdef SPLITTEST
19314     splitcases = 0;
19315 #endif
19316 
19317 #ifdef PLUGIN_INIT
19318     PLUGIN_INIT;
19319 #endif
19320 
19321     minpolydeg = -1;
19322     minpolyconnec = -1;
19323 
19324     if (pswitch && bswitch)                     bipartite_dispatch();
19325     else if (pswitch && minconnec >= 4)         polytope_c4_dispatch();
19326     else if (pswitch && minconnec < 4)          polytope_dispatch();
19327     else if (polygonsize>=0)                    polygon_dispatch();
19328     else if (bswitch)                           eulerian_dispatch();
19329     else if (qswitch)                           quadrangulation_dispatch();
19330     else if (minconnec >= 5 || minimumdeg >= 5) min5_dispatch();
19331     else if (minconnec >= 4 || minimumdeg >= 4) min4_dispatch();
19332     else                                        simple_dispatch();
19333 
19334 #if CPUTIME
19335     times(&timestruct1);
19336 #endif
19337 
19338     totalout = totalout_op = 0;
19339     for (i = 0; i < 6; ++i)
19340     {
19341 	totalout += nout[i];
19342 	if (oswitch) totalout_op += nout_op[i];
19343     }
19344 
19345     dosummary = 1;
19346 #ifdef SUMMARY
19347     nv = maxnv;
19348     SUMMARY();
19349 #endif
19350 
19351 #ifdef SPLITTEST
19352     PRINTBIG(msgfile,splitcases);
19353     fprintf(msgfile," splitting cases at level=%d",splitlevel);
19354 #if CPUTIME
19355     fprintf(msgfile,"; cpu=%.2f sec\n",
19356 	(double)(timestruct1.tms_utime+timestruct1.tms_stime
19357               -timestruct0.tms_utime-timestruct0.tms_stime) / (double)CLK_TCK);
19358 #else
19359     fprintf(msgfile,"\n");
19360 #endif
19361     return 0;
19362 #endif
19363 
19364     if (!dosummary) return 0;
19365 
19366     if (oswitch && vswitch)
19367     {
19368 	PRINTBIG(msgfile,totalout);
19369 	fprintf(msgfile," isomorphism classes\n");
19370     }
19371 
19372     PRINTBIG(msgfile,(oswitch ? totalout_op : totalout));
19373     fprintf(msgfile," %s",outtypename);
19374     if (uswitch) fprintf(msgfile," generated");
19375     else         fprintf(msgfile," written to %s",outfilename);
19376 #if CPUTIME
19377     fprintf(msgfile,"; cpu=%.2f sec\n",
19378 	    (double)(timestruct1.tms_utime+timestruct1.tms_stime
19379 	      -timestruct0.tms_utime+timestruct0.tms_stime) / (double)CLK_TCK);
19380 #else
19381     fprintf(msgfile,"\n");
19382 #endif
19383     if (Vswitch)
19384     {
19385 	fprintf(msgfile,"Suppressed ");
19386 	PRINTBIG(msgfile,nout_V);
19387 	fprintf(msgfile," with trivial group.\n");
19388     }
19389 
19390 #ifdef STATS
19391     if (Gswitch)
19392     {
19393         PRINTBIG(msgfile,numrooted);
19394         fprintf(msgfile," rooted maps\n");
19395         fprintf(msgfile,"Number with trivial group: ");
19396         PRINTBIG(msgfile,ntriv);
19397         fprintf(msgfile,"\n");
19398     }
19399     else if (polygonsize == 0)
19400     {
19401         fprintf(msgfile,"Rooted counts by outside face:\n");
19402         for (i = 3; i < maxnv; ++i)
19403             if (numbigface[i] > 0)
19404             {
19405                 fprintf(msgfile,"%2d: ",i);
19406                 PRINTBIG(msgfile,numbigface[i]);
19407                 fprintf(msgfile,"\n");
19408             }
19409     }
19410 #ifdef STATS2
19411     fprintf(msgfile,"Counts by number of twos:");
19412     for (i = 0; i < maxnv; ++i)
19413 	if (numtwos[i] > 0)
19414             {
19415                 fprintf(msgfile," %d:",i);
19416                 PRINTBIG(msgfile,numtwos[i]);
19417             }
19418     fprintf(msgfile,"\n");
19419 #endif
19420 #endif
19421 
19422     return 0;
19423 }
19424