/* testg.c : Find properties of graphs. This is the source file for both pickg (select by property) and countg (count by property).
Version 2.2 of June 2022. */ /* TODO - write a header if input has one;
Fix clunky practice of storing a pointer in a long long. */
#define HELPTEXT \ " countg : Count graphs according to their properties.\n\
pickg : Select graphs according to their properties.\n\
\n\
ifile, ofile : Input and output files.\n\ '-'and missing names imply stdin and stdout.\n\
\n\
Miscellaneous switches:\n\
-p# -p#:# Specify range of input lines (first is 1)\n\
May fail if input is incremental.\n\
-f With -p, assume input lines of fixed length\n\
(only used with a file in graph6/digraph6 format)\n\
-v Negate all constraints (but not -p)\n\
-X Reverse selection (but -p still observed)\n\
-V List properties of every input matching constraints.\n\
-l Put a blank line whenever the first parameter changes,\n\ if there are at least two parameters.\n\
-1 Write output as lines of numbers separated by spaces,\n\
with 0/1 for boolean and both endpoints of ranges given\n\
separately even if they are the same, and the count at\n\
the end of the line. Also, no total is written.\n\
-2 The same as -1 but counts are not written.\n\
-q Suppress informative output.\n\
\n\
Constraints:\n\
Numerical constraints (shown here with following #) can take\n\
a single integer value, or a range like #:#,#:, or :#. Each\n\
can also be preceded by '~', which negates it. (For example,\n\
-~D2:4 will match any maximum degree which is _not_ 2, 3, or 4.)\n\
Constraints are applied to all input graphs, and only those\n\
which match all constraints are counted or selected.\n\
\n\
-n# number of vertices -e# number of edges\n\
-ee# number of non-edges (including loops for digraphs)\n\
-L# number of loops -C strongly connected\n\
-LL# number of 2-cycles -cc# number of components\n\
-d# minimum (out-)degree -D# maximum (out-)degree\n\
-m# vertices of min (out-)degree -M# vertices of max (out-)degree\n\
-u# minimum (in-)degree -U# maximum (in-)degree\n\
-s# vertices of min (in-)degree -S# vertices of max (in-)degree\n\
-r regular -b bipartite\n\
-z# radius -Z# diameter\n\
-g# girth (0=acyclic) -Y# total number of cycles\n\
-h# maximum independent set -k# maximum clique\n\
-T# number of triangles -K# number of maximal cliques\n\
-TT# number independent sets of size 3\n\
-B# smallest possible first side of a bipartition (0 if nonbipartite)\n\
-H# number of induced cycles -W# number of 4-cycles\n\
-E Eulerian (all degrees are even, connectivity not required)\n\
-a# group size -o# orbits -F# fixed points -t vertex-transitive\n\
-c# connectivity (only implemented for 0,1,2).\n\
-i# min common nbrs of adjacent vertices; -I# maximum\n\
-j# min common nbrs of non-adjacent vertices; -J# maximum\n\
-x# number of sources -xx# number of sinks\n\
-WW# number of diamonds\n\
\n\
Sort keys:\n\
Counts are made for all graphs passing the constraints. Counts\n\
are given separately for each combination of values occurring for\n\
the properties listed as sort keys. A sort key is introduced by\n\ '--'and uses one of the letters known as constraints. These can\n\
be combined: --n --e --r is the same as --ne --r and --ner.\n\
The order of sort keys is significant.\n\
A comma can be used as a separator.\n\
The sort key ':' has a special purpose: the values of sort keys\n\
following ':' are given as ranges rather than creating a separate\n\
line for each value. For example --e:zZ will give the ranges of\n\
radius and diameter that occur for each number of edges.\n\
The output format matches the input, except that sparse6 is used\n\
to output an incremental graph whose predecessor is not output.\n"
1. Add entries to constraint[], following the examples there. If several things are computed at the same time, link them together such as for z and Z. It doesn't matter which is first, provided the prereq field points to the first one.
2. Add code to compute() to compute the value(s) of the parameter. Probably this means calling an external procedure then setting some VAL() and COMPUTED() values.
3. Update HELPTEXT.
External user-defined parameters: A general integer-valued parameter can be compiled into this program if USERDEF is defined as the function name at compile time. In this case the parameter is selected using the letter 'Q'. The name of the parameter is "userdef" unless USERDEFNAME is defined. The function is called with the parameters (graph *g, int m, int n) and must return an int value. If it works also for digraphs, also define USERDEFDIGRAPH (with any value).
Alternatively, use LUSERDEF for a function returning a long int. You can't use both USERDEF and LUSERDEF; choose one.
How the program tells if it is a picker or counter or both: > If either DOPICK or DOCOUNT is defined (or both), that determines the nature of the program regardless of its name. > If neither DOPICK nor DOCOUNT are defined, the nature is determined by which of the strings "pick" and "count" occur in the last part of the program name (the part after the final "/" if any). > It is an error if none of these rules provide an answer.
*/
#ifdefined(USERDEF) && defined(LUSERDEF) #error It is not allowed to define both USERDEF and LUSERDEF. #endif
#ifdef USERDEF int USERDEF(graph*,int,int); #endif
#ifdef LUSERDEF long LUSERDEF(graph*,int,int); #endif
#define MAXKEYS NUMCONSTRAINTS /* Maximum number of keys to sort by */
/* splay_st is the generic structure of a splay tree node. The data[] field has varying lengths according to need. This program uses two splay trees: one for counts and one for large data items.
*/
typedefstruct node_st /* variant for count tree */
{ struct splay_st *left,*right,*parent;
nauty_counter count;
range val[MAXKEYS]; /* Need this big? */
} count_node;
typedefstruct value_st /* variant for value tree */
{ struct splay_st *left,*right,*parent;
size_t size;
value_t data[1];
} value_node;
staticint
add_count(count_node *newval, count_node *oldval) /* add new value into old value; numsplitkeys are the the same - update ranges for other keys.
newval has equal lo & hi values. */
{ int i;
group_node *sza,*szb;
++oldval->count;
for (i = numsplitkeys; i < numkeys; ++i)
{ if (VALTYPE(key[i]) == GROUPSIZE)
{
sza = (group_node*)newval->val[i].lo;
szb = (group_node*)oldval->val[i].lo; if (compare_groupnodes(sza,szb) < 0)
oldval->val[i].lo = newval->val[i].lo;
szb = (group_node*)oldval->val[i].hi; if (compare_groupnodes(sza,szb) > 0)
oldval->val[i].hi = newval->val[i].lo;
} elseif (newval->val[i].lo < oldval->val[i].lo)
oldval->val[i].lo = newval->val[i].lo; elseif (newval->val[i].lo > oldval->val[i].hi)
oldval->val[i].hi = newval->val[i].lo;
}
if (oneswitch)
{ for (i = 0; i < numkeys; ++i)
{
ki = key[i]; if (i > 0) fprintf(f," ");
if (VALTYPE(ki) == BOOLTYPE)
{ if (!VAL(ki)) fprintf(f,"0"); else fprintf(f,"1");
} elseif (VALTYPE(ki) == GROUPSIZE)
write_group_size(f,(group_node*)VAL(ki)); else
fprintf(f,VALUE_FMT,VAL(ki));
}
} else
{ for (i = 0; i < numkeys; ++i)
{
ki = key[i]; if (i > 0) fprintf(f,"; ");
staticvoid
groupstats(graph *g, boolean digraph, int m, int n, group_node *sz, int *numorbits, int *fixedpts) /* Find the automorphism group of the undirected graph g.
Return the group size and number of orbits and fixed points. */
{ #if MAXN int lab[MAXN],ptn[MAXN],orbits[MAXN]; int count[MAXN];
set active[MAXM];
setword workspace[24*MAXM]; #else
DYNALLSTAT(int,lab,lab_sz);
DYNALLSTAT(int,ptn,ptn_sz);
DYNALLSTAT(int,orbits,orbits_sz);
DYNALLSTAT(int,count,count_sz);
DYNALLSTAT(set,active,active_sz);
DYNALLSTAT(setword,workspace,workspace_sz); #endif int i; int fixed; int numcells,code;
statsblk stats; static DEFAULTOPTIONS_GRAPH(options);
staticvoid
compute(graph *g, int m, int n, int code, boolean digraph) /* Compute property i assuming the prerequisites are known. */
{ int mind,maxd,mincount,maxcount; int minind,maxind,minincount,maxincount; int rad,diam,loops; unsignedlong ned;
boolean eul;
group_node sz; int norbs,fixedpts; int minadj,maxadj,minnon,maxnon; int sources,sinks;
case I_c: if (isbiconnected(g,m,n)) VAL(I_c) = 2; elseif (isconnected(g,m,n)) VAL(I_c) = 1; else VAL(I_c) = 0;
COMPUTED(I_c) = TRUE; break;
case I_n: case I_d: case I_D: case I_E: case I_r: case I_o: case I_t: case I_m: case I_M:
fprintf(stderr,">E Property %d should be known already\n",code); exit(1);
case I_Y:
VAL(I_Y) = cyclecount(g,m,n);
COMPUTED(I_Y) = TRUE; break;
case I_H:
VAL(I_H) = indcyclecount(g,m,n);
COMPUTED(I_H) = TRUE; break;
case I_T: if (digraph) VAL(I_T) = numdirtriangles(g,m,n); else VAL(I_T) = numtriangles(g,m,n);
COMPUTED(I_T) = TRUE; break;
case I_W:
VAL(I_W) = numsquares(g,m,n);
COMPUTED(I_W) = TRUE; break;
case I_WW:
VAL(I_WW) = numdiamonds(g,m,n);
COMPUTED(I_WW) = TRUE; break;
case I_TT:
VAL(I_TT) = numind3sets(g,m,n);
COMPUTED(I_TT) = TRUE; break;
case I_x: case I_xx:
sources_sinks(g,m,n,&sources,&sinks);
VAL(I_x) = sources;
VAL(I_xx) = sinks; break;
case I_i: case I_I: case I_j: case I_J:
commonnbrs(g,&minadj,&maxadj,&minnon,&maxnon,m,n);
VAL(I_i) = minadj;
VAL(I_I) = maxadj;
VAL(I_j) = minnon;
VAL(I_J) = maxnon;
COMPUTED(I_i) = COMPUTED(I_I) = TRUE;
COMPUTED(I_j) = COMPUTED(I_J) = TRUE; break;
staticvoid
decodekeys(char *s) /* Extract key symbols from -- string */
{ int i,j,k;
for (i = 0; s[i] != '\0'; ++i)
{ if (s[i] == ':')
{ if (rangemarkerseen)
{
fprintf(stderr,">E --: is only allowed once\n"); exit(1);
}
rangemarkerseen = TRUE; continue;
}
if (vswitch)
{ for (j = 0; j < NUMCONSTRAINTS; ++j) if (ISCONSTRAINT(j)) INVERSE(j) = !INVERSE(j);
}
if (!qswitch)
{
fprintf(stderr,">A %s",argv[0]); if (fswitch || pswitch || oneswitch || twoswitch)
fprintf(stderr," -"); if (fswitch) fprintf(stderr,"f"); if (oneswitch) fprintf(stderr,"1"); if (twoswitch) fprintf(stderr,"2"); if (pswitch) writeparamrange(stderr,'p',FALSE,pval1,pval2);
if (numkeys > 0)
{
fprintf(stderr," --"); for (j = 0; j < numkeys; ++j) if (j == numsplitkeys && j != 0)
{ if (ISDOUBLED(key[j]))
fprintf(stderr,":%c%c",SYMBOL(key[j]),SYMBOL(key[j])); else
fprintf(stderr,":%c",SYMBOL(key[j]));
} else
{ if (ISDOUBLED(key[j]))
fprintf(stderr,"%c%c",SYMBOL(key[j]),SYMBOL(key[j])); else
fprintf(stderr,"%c",SYMBOL(key[j]));
}
}
if (havecon) fprintf(stderr," -"); for (j = 0; j < NUMCONSTRAINTS; ++j) if (ISCONSTRAINT(j))
{ if (INVERSE(j)) fprintf(stderr,"~"); if (ISDOUBLED(j))
{ if (VALTYPE(j) == BOOLTYPE)
fprintf(stderr,"%c%c",SYMBOL(j),SYMBOL(j)); else
writeparamrange(stderr,SYMBOL(j),TRUE,LO(j),HI(j));
} else
{ if (VALTYPE(j) == BOOLTYPE)
fprintf(stderr,"%c",SYMBOL(j)); else
writeparamrange(stderr,(int)SYMBOL(j),FALSE,LO(j),HI(j));
}
}
if (argnum > 0) fprintf(stderr," %s",infilename); if (argnum > 1) fprintf(stderr," %s",outfilename);
fprintf(stderr,"\n");
fflush(stderr);
}
oneswitch = (oneswitch || twoswitch);
if (infilename && infilename[0] == '-') infilename = NULL;
infile = opengraphfile(infilename,&codetype,fswitch,
pswitch ? pval1 : 1); if (!infile) exit(1); if (!infilename) infilename = "stdin";
/* outcode is ignored unless a header is written */ if ((codetype&SPARSE6)) outcode = SPARSE6; elseif ((codetype&DIGRAPH6)) outcode = DIGRAPH6; else outcode = GRAPH6;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.