Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F27035952
naututil.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Authored By
Unknown
Size
102 KB
Referenced Files
None
Subscribers
None
naututil.c
View Options
/*****************************************************************************
* *
* miscellaneous utilities for use with nauty 2.6. *
* None of these procedures are needed by nauty, but all are by dreadnaut. *
* *
* Copyright (1984-2016) Brendan McKay. All rights reserved. *
* Subject to waivers and disclaimers in nauty.h. *
* *
* CHANGE HISTORY *
* 10-Nov-87 : final changes for version 1.2 *
* 5-Dec-87 : changes made for version 1.3 : *
* - added procedures readinteger() and readstring() *
* - replaced all uses of fscanf() by appropriate uses *
* of readinteger() or readstring() *
* - "N:" is now illegal in readgraph() if N is too large *
* or too small *
* 28-Sep-88 : renamed to version 1.4 (no changes to this file) *
* 23-Mar-89 : changes for version 1.5 : *
* - declared key in hash() *
* - changed file name to naututil.c *
* 29-Mar-89 : - declared workperm[] and workset[], and modified *
* many routines to use them. *
* - added putmapping() *
* - reworked some code in mathon() and rangraph() *
* 3-Apr-89 : - changed putorbits() to use O(n) algorithm *
* 5-Apr-89 : - modifed readgraph() to not require fresh line *
* - changed MAKEEMPTY uses to EMPTYSET uses *
* 26-Apr-89 : - moved ptncode() and equitable() to nautaux.c *
* - added putquotient() *
* 18-Aug-89 : - modified putset() to use "i:j" syntax optionally *
* - modified putorbits() to use putset() *
* - modified calling sequence for mathon() *
* 19-Aug-90 : - changed delimeter arg of copycomment to int *
* 14-Oct-90 : renamed to version 1.6 (no changes to this file) *
* 23-Jan-91 : changes for version 1.7 : *
* - fixed bug in complement() *
* 27-Aug-92 : - made linelength <= 0 mean no line breaks *
* 5-Jun-93 : renamed to version 1.7+ (no changes to this file) *
* 18-Aug-93 : renamed to version 1.8 (no changes to this file) *
* 17-Sep-93 : renamed to version 1.9 (no changes to this file) *
* 13-Jul-96 : changes for version 2.0 : *
* - added dynamic allocation *
* - added limit parameter to readstring *
* - added readvperm() and sublabel() *
* 31-Aug-96 : - converted from RAN to KRAN *
* 6-Feb-97 : - corrected DYNALLOC1 call in putmapping *
* 10-Dec-97 : - KRAN now initialises automatically *
* 9-Jan-00 : - added naututil_check() *
* 12-Feb-00 : - some minor code formatting *
* 16-Nov-00 : - changes as listed in nauty.h *
* 23-Apr-01 : changes for version 2.1 : *
* - removed EXTDEFS *
* 2-Jun-01 : - added converse() *
* 21-Nov-01 : use NAUTYREQUIRED in naututil_check() *
* 11-Apr-03 : changes for version 2.2 : *
* - added rangraph2() *
* 17-Nov-03 : changed INFINITY to NAUTY_INFINITY *
* 10-Dec-06 : removed BIGNAUTY *
* 4-Nov-09 : added readgraph_sg, putgraph_sg, putcanon_sg *
* 10-Nov-09 : removed shortish and permutation types *
* 14-Nov-09 : added relabel_sg(), putdegs_sg(), sublabel_sg() *
* 19-Nov-09 : added individualise() *
* 20-Nov-09 : added hashgraph_sg(), listhash(), hashgraph() *
* 19-Dec-09 : added ranreg_sg(), rangraph2_sg() *
* 21-May-10 : conform to type changes in sparsegraph *
* 5-Jun-10 : add mathon_sg() *
* 10-Jun-10 : add putquotient_sg() and complement_sg() *
* 26-Jan-11 : fix nde error in sublabel_sg() *
* 15-Jan-12 : add TLS_ATTR attributes *
* 3-Mar-12 : add putorbitsplus() and putset_firstbold() *
* : write orbit sizes if not trivial *
* 17-Mar-12 : move seed definition to naututil.h *
* 20-Sep-12 : allow quoted strings in readstring() *
* 20-Sep-12 : the first argument of ungetc is int, not char *
* 4-Mar-13 : remove a side-effect issue in setinter() *
* 17-Dec-15 : add readgraph_swg() and update putgraph_sg() *
* 22-Jan-16 : add readintger_sl() and getint_sl() *
* 29-Feb-16 : add subpartition() *
* 6-Apr-16 : add countcells(), make subpartition return a count *
* *
*****************************************************************************/
#define ONE_WORD_SETS
#include
"naututil.h"
/* which includes nauty.h, nautinv.h and stdio.h */
#include
"nausparse.h"
#if MAXM==1
#define M 1
#else
#define M m
#endif
#if !MAXN
DYNALLSTAT
(
int
,
workperm
,
workperm_sz
);
DYNALLSTAT
(
set
,
workset
,
workset_sz
);
#else
static
TLS_ATTR
int
workperm
[
MAXN
+
2
];
/* used for scratch purposes */
static
TLS_ATTR
set
workset
[
MAXM
];
/* used for scratch purposes */
#endif
#define ECHUNKSIZE 1000
/* should be a multiple of 2 */
typedef
struct
echunk
{
struct
echunk
*
next
;
int
edge
[
ECHUNKSIZE
];}
echunk
;
static
TLS_ATTR
echunk
first_echunk
=
{
NULL
,{
0
}};
typedef
struct
echunkw
{
struct
echunkw
*
next
;
\
struct
{
int
v1
,
v2
;
sg_weight
wt
;}
edge
[
ECHUNKSIZE
];}
echunkw
;
static
TLS_ATTR
echunkw
first_echunkw
=
{
NULL
,{
0
,
0
,
0
}};
#ifdef NLMAP
#define GETNW(c,f) do c = getc(f); while (c==' '||c=='\t')
#define GETNWC(c,f) do c = getc(f); while (c==' '||c==','||c=='\t')
#define GETNWL(c,f) do c = getc(f); while (c==' '||c=='\n'||c=='\t')
#else
#define GETNW(c,f) do c = getc(f); while (c==' '||c=='\t'||c=='\r')
#define GETNWC(c,f) do c = getc(f); while (c==' '||c==','||c=='\t'||c=='\r')
#define GETNWL(c,f) do c = getc(f); while (c==' '||c=='\n'||c=='\t'||c=='\r')
#endif
#define ISDIGIT(c) ((c) >= '0' && (c) <= '9')
static
const
long
fuzz1
[]
=
{
1984625421L
,
971524688L
,
1175081625L
,
377165387L
};
static
const
long
fuzz2
[]
=
{
2001381726L
,
1615243355L
,
191176436L
,
1212176501L
};
#define FUZZ1(x) ((x) ^ fuzz1[(x)&3L])
#define FUZZ2(x) ((x) ^ fuzz2[(x)&3L])
#define SORT_OF_SORT 1
#define SORT_NAME sort1int
#define SORT_TYPE1 int
#include
"sorttemplates.c"
/* define sort1int(a,n) */
/*****************************************************************************
* *
* setinter(set1,set2,m) = the number of elements in the intersection of *
* the sets set1 and set2. *
* *
*****************************************************************************/
int
setinter
(
set
*
set1
,
set
*
set2
,
int
m
)
{
setword
x
;
#if MAXM==1
if
((
x
=
*
set1
&
*
set2
)
!=
0
)
return
POPCOUNT
(
x
);
else
return
0
;
#else
int
count
,
i
;
count
=
0
;
for
(
i
=
m
;
--
i
>=
0
;)
{
if
((
x
=
(
*
set1
&
*
set2
))
!=
0
)
count
+=
POPCOUNT
(
x
);
++
set1
;
++
set2
;
}
return
count
;
#endif
}
/*****************************************************************************
* *
* setsize(set1,m) = the number of elements in the set set1. *
* *
*****************************************************************************/
int
setsize
(
set
*
set1
,
int
m
)
{
#if MAXM==1
if
(
set1
!=
0
)
return
POPCOUNT
(
*
set1
);
else
return
0
;
#else
int
count
,
i
;
setword
x
;
count
=
0
;
for
(
i
=
m
;
--
i
>=
0
;)
if
((
x
=
*
set1
++
)
!=
0
)
count
+=
POPCOUNT
(
x
);
return
count
;
#endif
}
/*****************************************************************************
* *
* flushline(f) reads from f until '\n' or EOF. *
* If non-trivial characters are skipped, the user is informed. *
* *
*****************************************************************************/
void
flushline
(
FILE
*
f
)
{
boolean
msg
;
int
c
;
msg
=
FALSE
;
while
((
c
=
getc
(
f
))
!=
EOF
&&
c
!=
'\n'
)
if
(
msg
)
PUTC
((
char
)
c
,
ERRFILE
);
else
if
(
c
!=
' '
&&
c
!=
'\t'
&&
c
!=
'\f'
&&
c
!=
'\r'
&&
c
!=
','
)
{
msg
=
TRUE
;
fprintf
(
ERRFILE
,
"input skipped : '%c"
,(
char
)
c
);
}
if
(
msg
)
fprintf
(
ERRFILE
,
"'
\n\n
"
);
}
/*****************************************************************************
* *
* readinteger(f,&i) reads an optionally-signed integer from f, preceded by *
* any amount of white space. The function value returned is TRUE if an *
* integer was found, FALSE otherwise. *
* *
*****************************************************************************/
boolean
readinteger
(
FILE
*
f
,
int
*
p
)
{
int
c
,
ans
,
minus
;
GETNWL
(
c
,
f
);
if
(
!
ISDIGIT
(
c
)
&&
c
!=
'-'
&&
c
!=
'+'
)
{
if
(
c
!=
EOF
)
ungetc
(
c
,
f
);
return
FALSE
;
}
minus
=
c
==
'-'
;
ans
=
(
c
==
'-'
||
c
==
'+'
?
0
:
c
-
'0'
);
c
=
getc
(
f
);
while
(
ISDIGIT
(
c
))
{
ans
*=
10
;
ans
+=
c
-
'0'
;
c
=
getc
(
f
);
}
if
(
c
!=
EOF
)
ungetc
(
c
,
f
);
*
p
=
(
minus
?
-
ans
:
ans
);
return
TRUE
;
}
/*****************************************************************************
* *
* readinteger_sl(f,&i) reads an optionally-signed integer from f, preceded *
* by any amount of white space except newlines. The function value *
* returned is TRUE if an integer was found, FALSE otherwise. *
* *
*****************************************************************************/
boolean
readinteger_sl
(
FILE
*
f
,
int
*
p
)
{
int
c
,
ans
,
minus
;
GETNW
(
c
,
f
);
if
(
!
ISDIGIT
(
c
)
&&
c
!=
'-'
&&
c
!=
'+'
)
{
if
(
c
!=
EOF
)
ungetc
(
c
,
f
);
return
FALSE
;
}
minus
=
c
==
'-'
;
ans
=
(
c
==
'-'
||
c
==
'+'
?
0
:
c
-
'0'
);
c
=
getc
(
f
);
while
(
ISDIGIT
(
c
))
{
ans
*=
10
;
ans
+=
c
-
'0'
;
c
=
getc
(
f
);
}
if
(
c
!=
EOF
)
ungetc
(
c
,
f
);
*
p
=
(
minus
?
-
ans
:
ans
);
return
TRUE
;
}
/*****************************************************************************
* *
* readstring(f,s,slen) reads a string from f. First any amount of white *
* space is skipped (including newlines). If the next character is a *
* double-quote, everything after that before the next double-quote or *
* newline is put into s. If the next character is not a double-quote, *
* everything before the next white space is put into s. A nul is added, *
* but no more than slen characters are ever put into s. The function *
* value is TRUE if a string was found and FALSE otherwise. *
* *
*****************************************************************************/
boolean
readstring
(
FILE
*
f
,
char
*
s
,
int
slen
)
{
int
c
;
char
*
slim
;
slim
=
s
+
slen
-
1
;
GETNWL
(
c
,
f
);
if
(
c
==
EOF
)
{
*
s
=
'\0'
;
return
FALSE
;
}
if
(
c
==
'"'
)
{
c
=
getc
(
f
);
while
(
c
!=
'"'
&&
c
!=
'\n'
&&
c
!=
'\r'
&&
c
!=
EOF
)
{
if
(
s
<=
slim
)
*
s
++
=
(
char
)
c
;
c
=
getc
(
f
);
}
if
(
c
!=
'"'
&&
c
!=
EOF
)
ungetc
(
c
,
f
);
}
else
{
if
(
s
<=
slim
)
*
s
++
=
(
char
)
c
;
c
=
getc
(
f
);
while
(
c
!=
' '
&&
c
!=
'\n'
&&
c
!=
'\t'
&&
c
!=
'\r'
&&
c
!=
EOF
)
{
if
(
s
<=
slim
)
*
s
++
=
(
char
)
c
;
c
=
getc
(
f
);
}
if
(
c
!=
EOF
)
ungetc
(
c
,
f
);
}
if
(
s
<=
slim
)
*
s
=
'\0'
;
else
*
slim
=
'\0'
;
return
TRUE
;
}
/*****************************************************************************
* *
* getint(f) reads an integer from f, optionally preceded by '=' *
* and white space. -1 is returned if the attempt was unsuccessful. *
* *
*****************************************************************************/
int
getint
(
FILE
*
f
)
{
int
i
,
c
;
GETNWL
(
c
,
f
);
if
(
c
!=
'='
)
ungetc
(
c
,
f
);
if
(
readinteger
(
f
,
&
i
))
return
i
;
else
return
-1
;
}
/*****************************************************************************
* *
* getint_sl(f) reads an integer from f, optionally preceded by '=' and *
* white space other than newlines. -1 is returned if the attempt was *
* unsuccessful. *
*****************************************************************************/
int
getint_sl
(
FILE
*
f
)
{
int
i
,
c
;
GETNW
(
c
,
f
);
if
(
c
!=
'='
)
ungetc
(
c
,
f
);
if
(
readinteger_sl
(
f
,
&
i
))
return
i
;
else
return
-1
;
}
/*****************************************************************************
* *
* putset(f,set1,curlenp,linelength,m,compress) writes the set set1 to *
* file f using at most linelength characters per line (excluding '\n'). *
* A value of linelength <= 0 dictates no line breaks at all. *
* *curlenp is the number of characters on the line so far; it is updated. *
* A range j1,j1+1,...,j2 for j2-j1>=2 is written as "j1:j2" if compress *
* is nonzero (eg. TRUE); otherwise each element is written separately. *
* No final '\n' is written. labelorg is used. *
* *
* FUNCTIONS CALLED: nextelement(),itos() *
* *
*****************************************************************************/
void
putset
(
FILE
*
f
,
set
*
set1
,
int
*
curlenp
,
int
linelength
,
int
m
,
boolean
compress
)
{
int
slen
,
j1
,
j2
;
char
s
[
40
];
j1
=
-1
;
while
((
j1
=
nextelement
(
set1
,
m
,
j1
))
>=
0
)
{
j2
=
j1
;
if
(
compress
)
{
while
(
nextelement
(
set1
,
m
,
j2
)
==
j2
+
1
)
++
j2
;
if
(
j2
==
j1
+
1
)
j2
=
j1
;
}
slen
=
itos
(
j1
+
labelorg
,
s
);
if
(
j2
>=
j1
+
2
)
{
s
[
slen
]
=
':'
;
slen
+=
1
+
itos
(
j2
+
labelorg
,
&
s
[
slen
+
1
]);
}
if
(
linelength
>
0
&&
*
curlenp
+
slen
+
1
>=
linelength
)
{
fprintf
(
f
,
"
\n
"
);
*
curlenp
=
3
;
}
fprintf
(
f
,
" %s"
,
s
);
*
curlenp
+=
slen
+
1
;
j1
=
j2
;
}
}
/*****************************************************************************
* *
* putset_firstbold(f,set1,curlenp,linelength,m,compress) is the same as *
* putset(f,set1,curlenp,linelength,m,compress) except that the first *
* element of the set is written bold. This is only useful when output is *
* to a device that interprets ANSI control sequences. *
* *
* FUNCTIONS CALLED: nextelement(),itos() *
* *
*****************************************************************************/
void
putset_firstbold
(
FILE
*
f
,
set
*
set1
,
int
*
curlenp
,
int
linelength
,
int
m
,
boolean
compress
)
{
int
slen
,
slen1
,
j1
,
j2
;
char
s
[
50
],
c
;
boolean
bold
;
bold
=
TRUE
;
j1
=
-1
;
while
((
j1
=
nextelement
(
set1
,
m
,
j1
))
>=
0
)
{
j2
=
j1
;
if
(
compress
)
{
while
(
nextelement
(
set1
,
m
,
j2
)
==
j2
+
1
)
++
j2
;
if
(
j2
==
j1
+
1
)
j2
=
j1
;
}
slen1
=
slen
=
itos
(
j1
+
labelorg
,
s
);
if
(
j2
>=
j1
+
2
)
{
s
[
slen
]
=
':'
;
slen
+=
1
+
itos
(
j2
+
labelorg
,
&
s
[
slen
+
1
]);
}
c
=
s
[
slen1
];
if
(
linelength
>
0
&&
*
curlenp
+
slen
+
1
>=
linelength
)
{
fprintf
(
f
,
"
\n
"
);
*
curlenp
=
3
;
}
if
(
bold
)
{
s
[
slen1
]
=
'\0'
;
fprintf
(
f
,
"
\033
[1m%s
\033
[0m"
,
s
);
s
[
slen1
]
=
c
;
fprintf
(
f
,
"%s"
,
&
s
[
slen1
]);
bold
=
FALSE
;
}
else
fprintf
(
f
,
" %s"
,
s
);
*
curlenp
+=
slen
+
1
;
j1
=
j2
;
}
}
/*****************************************************************************
* *
* readgraph(f,g,digraph,prompt,edit,linelength,m,n) reads a graph g from f. *
* Commands: (There is always a "current vertex" v, initially labelorg; *
* n is an unsigned integer.) *
* n : add edge (v,n) *
* -n : delete edge (v,n) *
* n: : set v := n, and exit if v >= n. *
* ? : type neighbours of vertex v *
* ; : increment v, and exit if v >= n. *
* . : exit *
* ! : skip rest of input line *
* *
* If digraph==FALSE, loops are illegal and (x,y) => (y,x) *
* If edit==FALSE, the graph is initialized to empty. *
* If prompt==TRUE, prompts are written to PROMPTFILE. *
* linelength is a limit on the number of characters per line caused by '?' *
* A value of linelength <= 0 dictates no line breaks at all. *
* labelorg is used. *
* *
* FUNCTIONS CALLED : putset() *
* *
*****************************************************************************/
void
readgraph
(
FILE
*
f
,
graph
*
g
,
boolean
digraph
,
boolean
prompt
,
boolean
edit
,
int
linelength
,
int
m
,
int
n
)
{
int
v
,
c
;
int
curlen
,
w
;
graph
*
gv
;
boolean
neg
;
if
(
!
edit
)
for
(
v
=
0
,
gv
=
g
;
v
<
n
;
++
v
,
gv
+=
M
)
EMPTYSET
(
gv
,
m
);
v
=
0
;
gv
=
g
;
neg
=
FALSE
;
while
(
TRUE
)
{
GETNWC
(
c
,
f
);
if
(
ISDIGIT
(
c
))
{
ungetc
(
c
,
f
);
readinteger
(
f
,
&
w
);
w
-=
labelorg
;
if
(
neg
)
{
neg
=
FALSE
;
if
(
w
<
0
||
w
>=
n
||
(
!
digraph
&&
w
==
v
))
fprintf
(
ERRFILE
,
"illegal edge (%d,%d) ignored
\n\n
"
,
v
+
labelorg
,
w
+
labelorg
);
else
{
DELELEMENT
(
gv
,
w
);
if
(
!
digraph
)
DELELEMENT
(
GRAPHROW
(
g
,
w
,
M
),
v
);
}
}
else
{
GETNWC
(
c
,
f
);
if
(
c
==
':'
)
if
(
w
<
0
||
w
>=
n
)
fprintf
(
ERRFILE
,
"illegal vertex number %d ignored
\n\n
"
,
w
+
labelorg
);
else
{
v
=
w
;
gv
=
GRAPHROW
(
g
,
v
,
M
);
}
else
{
ungetc
(
c
,
f
);
if
(
w
<
0
||
w
>=
n
||
(
!
digraph
&&
w
==
v
))
fprintf
(
ERRFILE
,
"illegal edge (%d,%d) ignored
\n\n
"
,
v
+
labelorg
,
w
+
labelorg
);
else
{
ADDELEMENT
(
gv
,
w
);
if
(
!
digraph
)
ADDELEMENT
(
GRAPHROW
(
g
,
w
,
M
),
v
);
}
}
}
}
else
switch
(
c
)
{
case
';'
:
neg
=
FALSE
;
++
v
;
if
(
v
>=
n
)
return
;
gv
=
GRAPHROW
(
g
,
v
,
M
);
break
;
case
'?'
:
neg
=
FALSE
;
fprintf
(
PROMPTFILE
,
"%2d : "
,
v
+
labelorg
);
curlen
=
5
;
putset
(
PROMPTFILE
,
gv
,
&
curlen
,
linelength
,
M
,
FALSE
);
fprintf
(
PROMPTFILE
,
";
\n
"
);
break
;
case
'\n'
:
neg
=
FALSE
;
if
(
prompt
)
fprintf
(
PROMPTFILE
,
"%2d : "
,
v
+
labelorg
);
break
;
case
EOF
:
case
'.'
:
return
;
case
'-'
:
neg
=
TRUE
;
break
;
case
'!'
:
do
c
=
getc
(
f
);
while
(
c
!=
'\n'
&&
c
!=
EOF
);
if
(
c
==
'\n'
)
ungetc
(
c
,
f
);
break
;
default
:
fprintf
(
ERRFILE
,
"illegal char '%c' - use '.' to exit
\n\n
"
,
(
char
)
c
);
}
}
}
/**************************************************************************/
void
ranreg_sg
(
sparsegraph
*
sg
,
int
degree
,
int
n
)
/* Make a random regular simple undirected graph.
* For MAXN!=0, the maximum degree is MAXREG.
* sg must be initialised
*/
{
long
i
,
k
,
v
,
w
;
boolean
ok
;
int
*
dd
,
*
ee
;
size_t
*
vv
,
nde
,
j
;
#if MAXN
int
p
[
MAXREG
*
MAXN
];
#else
DYNALLSTAT
(
int
,
p
,
p_sz
);
DYNALLOC2
(
int
,
p
,
p_sz
,
degree
,
n
,
"genrang"
);
#endif
nde
=
(
size_t
)
n
*
(
size_t
)
degree
;
SG_ALLOC
(
*
sg
,
n
,
nde
,
"ranreg_sg"
);
SG_VDE
(
sg
,
vv
,
dd
,
ee
);
DYNFREE
(
sg
->
w
,
sg
->
wlen
);
sg
->
nv
=
n
;
sg
->
nde
=
nde
;
for
(
i
=
j
=
0
;
i
<
n
;
++
i
)
for
(
k
=
0
;
k
<
degree
;
++
k
)
p
[
j
++
]
=
i
;
for
(
i
=
0
;
i
<
n
;
++
i
)
vv
[
i
]
=
i
*
(
size_t
)
degree
;
do
{
ok
=
TRUE
;
for
(
j
=
nde
;
j
>
0
;
j
-=
2
)
{
i
=
KRAN
(
j
-1
);
k
=
p
[
i
];
if
(
k
==
p
[
j
-1
])
break
;
p
[
i
]
=
p
[
j
-2
];
p
[
j
-2
]
=
k
;
}
if
(
j
>
0
)
{
ok
=
FALSE
;
continue
;
}
for
(
i
=
0
;
i
<
n
;
++
i
)
dd
[
i
]
=
0
;
for
(
j
=
nde
;
j
>
0
;
)
{
v
=
p
[
--
j
];
w
=
p
[
--
j
];
if
(
v
!=
w
)
{
for
(
i
=
dd
[
w
];
--
i
>=
0
;)
if
(
ee
[
vv
[
w
]
+
i
]
==
v
)
break
;
if
(
i
>=
0
)
{
ok
=
FALSE
;
break
;
}
}
ee
[
vv
[
w
]
+
(
dd
[
w
]
++
)]
=
v
;
ee
[
vv
[
v
]
+
(
dd
[
v
]
++
)]
=
w
;
}
}
while
(
!
ok
);
}
/*****************************************************************************
* *
* readgraph_sg(f,sg,digraph,prompt,linelength,n) reads a graph g from f. *
* Commands: (There is always a "current vertex" v, initially labelorg; *
* n is an unsigned integer.) *
* n : add edge (v,n) *
* -n : delete edge (v,n) *
* n: : set v := n, and exit if v >= n. *
* ? : type neighbours of vertex v ** NOT IMPLEMENTED ** *
* ; : increment v, and exit if v >= n. *
* . : exit *
* ! : skip rest of input line *
* sg must be initialised *
* *
* If digraph==FALSE, loops are illegal and (x,y) => (y,x) *
* If prompt==TRUE, prompts are written to PROMPTFILE. *
* linelength is a limit on the number of characters per line caused by '?' *
* A value of linelength <= 0 dictates no line breaks at all. *
* labelorg is used. *
* *
*****************************************************************************/
void
readgraph_sg
(
FILE
*
f
,
sparsegraph
*
sg
,
boolean
digraph
,
boolean
prompt
,
int
linelength
,
int
n
)
{
int
i
,
j
,
k
,
vv
,
ww
,
c
;
boolean
neg
,
done
;
int
*
d
,
*
e
,
*
evi
;
echunk
*
ec
,
*
ecnext
,
*
ec_end
;
size_t
ned
,
*
v
,
iec
,
iec_end
;
sg
->
nv
=
n
;
DYNALLOC1
(
size_t
,
sg
->
v
,
sg
->
vlen
,
n
,
"malloc"
);
DYNALLOC1
(
int
,
sg
->
d
,
sg
->
dlen
,
n
,
"malloc"
);
DYNFREE
(
sg
->
w
,
sg
->
wlen
);
v
=
sg
->
v
;
d
=
sg
->
d
;
for
(
i
=
0
;
i
<
n
;
++
i
)
d
[
i
]
=
0
;
ec
=
&
first_echunk
;
iec
=
0
;
vv
=
0
;
neg
=
done
=
FALSE
;
while
(
!
done
)
{
GETNWC
(
c
,
f
);
if
(
ISDIGIT
(
c
))
{
ungetc
(
c
,
f
);
readinteger
(
f
,
&
ww
);
ww
-=
labelorg
;
if
(
neg
)
{
neg
=
FALSE
;
if
(
ww
<
0
||
ww
>=
n
||
(
!
digraph
&&
ww
==
vv
))
fprintf
(
ERRFILE
,
"illegal edge (%d,%d) ignored
\n\n
"
,
vv
+
labelorg
,
ww
+
labelorg
);
else
{
if
(
iec
==
ECHUNKSIZE
)
{
if
(
!
ec
->
next
)
{
ecnext
=
(
echunk
*
)
ALLOCS
(
1
,
sizeof
(
echunk
));
if
(
!
ecnext
)
alloc_error
(
"malloc"
);
ecnext
->
next
=
NULL
;
ec
->
next
=
ecnext
;
}
ec
=
ec
->
next
;
iec
=
0
;
}
ec
->
edge
[
iec
++
]
=
vv
;
ec
->
edge
[
iec
++
]
=
-1
-
ww
;
++
d
[
vv
];
if
(
!
digraph
&&
ww
!=
vv
)
++
d
[
ww
];
}
}
else
{
GETNWC
(
c
,
f
);
if
(
c
==
':'
)
{
if
(
ww
<
0
||
ww
>=
n
)
fprintf
(
ERRFILE
,
"illegal vertex number %d ignored
\n\n
"
,
ww
+
labelorg
);
else
vv
=
ww
;
}
else
{
ungetc
(
c
,
f
);
if
(
ww
<
0
||
ww
>=
n
||
(
!
digraph
&&
ww
==
vv
))
fprintf
(
ERRFILE
,
"illegal edge (%d,%d) ignored
\n\n
"
,
vv
+
labelorg
,
ww
+
labelorg
);
else
{
if
(
iec
==
ECHUNKSIZE
)
{
if
(
!
ec
->
next
)
{
ecnext
=
(
echunk
*
)
ALLOCS
(
1
,
sizeof
(
echunk
));
if
(
!
ecnext
)
alloc_error
(
"malloc"
);
ecnext
->
next
=
NULL
;
ec
->
next
=
ecnext
;
}
ec
=
ec
->
next
;
iec
=
0
;
}
ec
->
edge
[
iec
++
]
=
vv
;
ec
->
edge
[
iec
++
]
=
ww
;
++
d
[
vv
];
if
(
!
digraph
&&
ww
!=
vv
)
++
d
[
ww
];
}
}
}
}
else
switch
(
c
)
{
case
';'
:
neg
=
FALSE
;
++
vv
;
if
(
vv
>=
n
)
done
=
TRUE
;
break
;
case
'?'
:
neg
=
FALSE
;
fprintf
(
ERRFILE
,
"Command
\'
?
\'
not implemented.
\n\n
"
);
break
;
case
'\n'
:
neg
=
FALSE
;
if
(
prompt
)
fprintf
(
PROMPTFILE
,
"%2d : "
,
vv
+
labelorg
);
break
;
case
EOF
:
case
'.'
:
done
=
TRUE
;
break
;
case
'-'
:
neg
=
TRUE
;
break
;
case
'!'
:
do
c
=
getc
(
f
);
while
(
c
!=
'\n'
&&
c
!=
EOF
);
if
(
c
==
'\n'
)
ungetc
(
c
,
f
);
break
;
default
:
fprintf
(
ERRFILE
,
"illegal char '%c' - use '.' to exit
\n\n
"
,
(
char
)
c
);
}
}
ned
=
0
;
for
(
i
=
0
;
i
<
n
;
++
i
)
ned
+=
d
[
i
];
DYNALLOC1
(
int
,
sg
->
e
,
sg
->
elen
,
ned
,
"malloc"
);
e
=
sg
->
e
;
v
[
0
]
=
0
;
for
(
i
=
1
;
i
<
n
;
++
i
)
v
[
i
]
=
v
[
i
-1
]
+
d
[
i
-1
];
for
(
i
=
0
;
i
<
n
;
++
i
)
d
[
i
]
=
0
;
iec_end
=
iec
;
ec_end
=
ec
;
iec
=
0
;
ec
=
&
first_echunk
;
if
(
ned
!=
0
)
while
(
TRUE
)
{
vv
=
ec
->
edge
[
iec
++
];
ww
=
ec
->
edge
[
iec
++
];
if
(
ww
>=
0
)
{
e
[
v
[
vv
]
+
(
d
[
vv
]
++
)]
=
ww
;
if
(
!
digraph
&&
ww
!=
vv
)
e
[
v
[
ww
]
+
(
d
[
ww
]
++
)]
=
vv
;
}
else
{
ww
=
-1
-
ww
;
for
(
i
=
0
;
i
<
d
[
vv
];
++
i
)
if
(
e
[
v
[
vv
]
+
i
]
==
ww
)
break
;
if
(
i
<
d
[
vv
])
{
e
[
v
[
vv
]
+
i
]
=
e
[
v
[
vv
]
+
d
[
vv
]
-1
];
--
d
[
vv
];
}
if
(
!
digraph
&&
ww
!=
vv
)
{
for
(
i
=
0
;
i
<
d
[
ww
];
++
i
)
if
(
e
[
v
[
ww
]
+
i
]
==
vv
)
break
;
if
(
i
<
d
[
ww
])
{
e
[
v
[
ww
]
+
i
]
=
e
[
v
[
ww
]
+
d
[
ww
]
-1
];
--
d
[
ww
];
}
}
}
if
(
iec
==
iec_end
&&
ec
==
ec_end
)
break
;
if
(
iec
==
ECHUNKSIZE
)
{
iec
=
0
;
ec
=
ec
->
next
;
}
}
sortlists_sg
(
sg
);
ned
=
0
;
for
(
i
=
0
;
i
<
n
;
++
i
)
{
if
(
d
[
i
]
>
1
)
{
evi
=
e
+
v
[
i
];
j
=
1
;
for
(
k
=
1
;
k
<
d
[
i
];
++
k
)
if
(
evi
[
k
]
!=
evi
[
j
-1
])
evi
[
j
++
]
=
evi
[
k
];
d
[
i
]
=
j
;
}
ned
+=
d
[
i
];
}
sg
->
nde
=
ned
;
}
/*****************************************************************************
* *
* readgraph_swg(f,sg,digraph,prompt,linelength,n) reads a sparse weighted *
* graph g from f. *
* Commands: (There is always a "current vertex" v, initially labelorg; *
* n is an unsigned integer, w is a weight.) *
* n : add edge (v,n) *
* -n : delete edge (v,n) *
* n: : set v := n, and exit if v >= n. *
* ? : type neighbours of vertex v ** NOT IMPLEMENTED ** *
* ; : increment v, and exit if v >= n. *
* . : exit *
* ! : skip rest of input line *
* w# : set the weight for the next edge only *
* W# : set the weight from now on *
* sg must be initialised *
* *
* If digraph==FALSE, loops are illegal and (x,y) => (y,x) *
* For digraphs, an unspecified opposite edge has weight SG_MINWEIGHT *
* If edges are inserted more than once, the largest weight counts. *
* If prompt==TRUE, prompts are written to PROMPTFILE. *
* linelength is a limit on the number of characters per line caused by '?' *
* A value of linelength <= 0 dictates no line breaks at all. *
* labelorg is used. *
* *
*****************************************************************************/
void
readgraph_swg
(
FILE
*
f
,
sparsegraph
*
sg
,
boolean
digraph
,
boolean
prompt
,
int
linelength
,
int
n
)
{
int
i
,
j
,
k
,
vv
,
ww
,
c
;
boolean
neg
,
done
;
int
*
d
,
*
e
,
*
evi
;
echunkw
*
ec
,
*
ecnext
,
*
ec_end
;
size_t
ned
,
*
v
,
iec
,
iec_end
;
sg_weight
*
wt
,
currwt
,
defwt
,
*
wvi
;
sg
->
nv
=
n
;
DYNALLOC1
(
size_t
,
sg
->
v
,
sg
->
vlen
,
n
,
"malloc"
);
DYNALLOC1
(
int
,
sg
->
d
,
sg
->
dlen
,
n
,
"malloc"
);
v
=
sg
->
v
;
d
=
sg
->
d
;
wt
=
sg
->
w
;
for
(
i
=
0
;
i
<
n
;
++
i
)
d
[
i
]
=
0
;
defwt
=
currwt
=
1
;
ec
=
&
first_echunkw
;
iec
=
0
;
vv
=
0
;
neg
=
done
=
FALSE
;
while
(
!
done
)
{
GETNWC
(
c
,
f
);
if
(
ISDIGIT
(
c
))
{
ungetc
(
c
,
f
);
readinteger
(
f
,
&
ww
);
ww
-=
labelorg
;
if
(
neg
)
{
neg
=
FALSE
;
if
(
ww
<
0
||
ww
>=
n
||
(
!
digraph
&&
ww
==
vv
))
fprintf
(
ERRFILE
,
"illegal edge (%d,%d) ignored
\n\n
"
,
vv
+
labelorg
,
ww
+
labelorg
);
else
{
if
(
iec
==
ECHUNKSIZE
)
{
if
(
!
ec
->
next
)
{
ecnext
=
(
echunkw
*
)
ALLOCS
(
1
,
sizeof
(
echunkw
));
if
(
!
ecnext
)
alloc_error
(
"malloc"
);
ecnext
->
next
=
NULL
;
ec
->
next
=
ecnext
;
}
ec
=
ec
->
next
;
iec
=
0
;
}
ec
->
edge
[
iec
].
v1
=
vv
;
ec
->
edge
[
iec
].
v2
=
-1
-
ww
;
ec
->
edge
[
iec
].
wt
=
currwt
;
++
iec
;
currwt
=
defwt
;
++
d
[
vv
];
if
(
ww
!=
vv
)
++
d
[
ww
];
}
}
else
{
GETNWC
(
c
,
f
);
if
(
c
==
':'
)
{
if
(
ww
<
0
||
ww
>=
n
)
fprintf
(
ERRFILE
,
"illegal vertex number %d ignored
\n\n
"
,
ww
+
labelorg
);
else
vv
=
ww
;
}
else
{
ungetc
(
c
,
f
);
if
(
ww
<
0
||
ww
>=
n
||
(
!
digraph
&&
ww
==
vv
))
fprintf
(
ERRFILE
,
"illegal edge (%d,%d) ignored
\n\n
"
,
vv
+
labelorg
,
ww
+
labelorg
);
else
{
if
(
iec
==
ECHUNKSIZE
)
{
if
(
!
ec
->
next
)
{
ecnext
=
(
echunkw
*
)
ALLOCS
(
1
,
sizeof
(
echunkw
));
if
(
!
ecnext
)
alloc_error
(
"malloc"
);
ecnext
->
next
=
NULL
;
ec
->
next
=
ecnext
;
}
ec
=
ec
->
next
;
iec
=
0
;
}
ec
->
edge
[
iec
].
v1
=
vv
;
ec
->
edge
[
iec
].
v2
=
ww
;
ec
->
edge
[
iec
].
wt
=
currwt
;
++
iec
;
currwt
=
defwt
;
++
d
[
vv
];
if
(
ww
!=
vv
)
++
d
[
ww
];
}
}
}
}
else
switch
(
c
)
{
case
';'
:
neg
=
FALSE
;
++
vv
;
if
(
vv
>=
n
)
done
=
TRUE
;
break
;
case
'?'
:
neg
=
FALSE
;
fprintf
(
ERRFILE
,
"Command
\'
?
\'
not implemented.
\n\n
"
);
break
;
case
'\n'
:
neg
=
FALSE
;
if
(
prompt
)
fprintf
(
PROMPTFILE
,
"%2d : "
,
vv
+
labelorg
);
break
;
case
EOF
:
case
'.'
:
done
=
TRUE
;
break
;
case
'-'
:
neg
=
TRUE
;
break
;
case
'w'
:
readinteger
(
f
,
&
currwt
);
if
(
currwt
<=
SG_MINWEIGHT
)
{
fprintf
(
ERRFILE
,
"Weight too small
\n\n
"
);
currwt
=
1
;
}
break
;
case
'W'
:
readinteger
(
f
,
&
currwt
);
if
(
currwt
<=
SG_MINWEIGHT
)
{
fprintf
(
ERRFILE
,
"Weight too small
\n\n
"
);
currwt
=
1
;
}
defwt
=
currwt
;
break
;
case
'!'
:
do
c
=
getc
(
f
);
while
(
c
!=
'\n'
&&
c
!=
EOF
);
if
(
c
==
'\n'
)
ungetc
(
c
,
f
);
break
;
default
:
fprintf
(
ERRFILE
,
"illegal char '%c' - use '.' to exit
\n\n
"
,
(
char
)
c
);
}
}
ned
=
0
;
for
(
i
=
0
;
i
<
n
;
++
i
)
ned
+=
d
[
i
];
DYNALLOC1
(
int
,
sg
->
e
,
sg
->
elen
,
ned
,
"malloc"
);
DYNALLOC1
(
sg_weight
,
sg
->
w
,
sg
->
wlen
,
ned
,
"malloc"
);
e
=
sg
->
e
;
wt
=
sg
->
w
;
v
[
0
]
=
0
;
for
(
i
=
1
;
i
<
n
;
++
i
)
v
[
i
]
=
v
[
i
-1
]
+
d
[
i
-1
];
for
(
i
=
0
;
i
<
n
;
++
i
)
d
[
i
]
=
0
;
iec_end
=
iec
;
ec_end
=
ec
;
iec
=
0
;
ec
=
&
first_echunkw
;
if
(
ned
!=
0
)
while
(
TRUE
)
{
vv
=
ec
->
edge
[
iec
].
v1
;
ww
=
ec
->
edge
[
iec
].
v2
;
currwt
=
ec
->
edge
[
iec
].
wt
;
++
iec
;
if
(
ww
>=
0
)
{
e
[
v
[
vv
]
+
d
[
vv
]]
=
ww
;
wt
[
v
[
vv
]
+
d
[
vv
]]
=
currwt
;
++
d
[
vv
];
if
(
ww
!=
vv
)
{
e
[
v
[
ww
]
+
d
[
ww
]]
=
vv
;
wt
[
v
[
ww
]
+
d
[
ww
]]
=
(
digraph
?
SG_MINWEIGHT
:
currwt
);
++
d
[
ww
];
}
}
else
{
ww
=
-1
-
ww
;
for
(
i
=
0
;
i
<
d
[
vv
];
++
i
)
if
(
e
[
v
[
vv
]
+
i
]
==
ww
)
break
;
if
(
i
<
d
[
vv
])
{
e
[
v
[
vv
]
+
i
]
=
e
[
v
[
vv
]
+
d
[
vv
]
-1
];
wt
[
v
[
vv
]
+
i
]
=
wt
[
v
[
vv
]
+
d
[
vv
]
-1
];
--
d
[
vv
];
}
if
(
ww
!=
vv
)
{
for
(
i
=
0
;
i
<
d
[
ww
];
++
i
)
if
(
e
[
v
[
ww
]
+
i
]
==
vv
)
break
;
if
(
i
<
d
[
ww
])
{
e
[
v
[
ww
]
+
i
]
=
e
[
v
[
ww
]
+
d
[
ww
]
-1
];
wt
[
v
[
ww
]
+
i
]
=
wt
[
v
[
ww
]
+
d
[
ww
]
-1
];
--
d
[
ww
];
}
}
}
if
(
iec
==
iec_end
&&
ec
==
ec_end
)
break
;
if
(
iec
==
ECHUNKSIZE
)
{
iec
=
0
;
ec
=
ec
->
next
;
}
}
sortlists_sg
(
sg
);
ned
=
0
;
for
(
i
=
0
;
i
<
n
;
++
i
)
{
if
(
d
[
i
]
>
1
)
{
evi
=
e
+
v
[
i
];
wvi
=
wt
+
v
[
i
];
j
=
1
;
for
(
k
=
1
;
k
<
d
[
i
];
++
k
)
{
if
(
evi
[
k
]
!=
evi
[
j
-1
])
{
evi
[
j
]
=
evi
[
k
];
wvi
[
j
]
=
wvi
[
k
];
++
j
;
}
else
if
(
wvi
[
k
]
>
wvi
[
j
-1
])
wvi
[
j
-1
]
=
wvi
[
k
];
}
d
[
i
]
=
j
;
}
ned
+=
d
[
i
];
}
sg
->
nde
=
ned
;
}
/*****************************************************************************
* *
* putgraph(f,g,linelength,m,n) writes a list of the edges of g to f *
* using at most linelength characters per line (excluding '\n'). *
* A value of linelength <= 0 dictates no line breaks at all within the *
* list for each vertex. *
* labelorg is used. *
* *
* FUNCTIONS CALLED: putset() *
* *
*****************************************************************************/
void
putgraph
(
FILE
*
f
,
graph
*
g
,
int
linelength
,
int
m
,
int
n
)
{
int
i
,
curlen
;
set
*
pg
;
for
(
i
=
0
,
pg
=
g
;
i
<
n
;
++
i
,
pg
+=
M
)
{
fprintf
(
f
,
"%3d : "
,
i
+
labelorg
);
curlen
=
7
;
putset
(
f
,
pg
,
&
curlen
,
linelength
,
M
,
FALSE
);
fprintf
(
f
,
";
\n
"
);
}
}
/*****************************************************************************
* *
* putgraph_sg(f,sg,linelength) writes a list of the edges of g to f *
* using at most linelength characters per line (excluding '\n'). *
* A value of linelength <= 0 dictates no line breaks at all within the *
* list for each vertex. *
* labelorg is used. *
* *
*****************************************************************************/
void
putgraph_sg
(
FILE
*
f
,
sparsegraph
*
sg
,
int
linelength
)
{
int
i
,
n
,
curlen
,
slen
;
int
*
d
,
*
e
;
size_t
*
v
,
j
;
sg_weight
*
wt
;
char
s
[
60
];
n
=
sg
->
nv
;
SWG_VDE
(
sg
,
v
,
d
,
e
,
wt
);
for
(
i
=
0
;
i
<
n
;
++
i
)
{
fprintf
(
f
,
"%3d : "
,
i
+
labelorg
);
curlen
=
7
;
for
(
j
=
v
[
i
];
j
<
v
[
i
]
+
d
[
i
];
++
j
)
{
if
(
wt
&&
wt
[
j
]
!=
1
)
{
s
[
0
]
=
'w'
;
if
(
wt
[
j
]
==
SG_MINWEIGHT
)
{
s
[
1
]
=
'X'
;
s
[
2
]
=
' '
;
slen
=
3
;
}
else
{
slen
=
2
+
itos
(
wt
[
j
],
s
+
1
);
s
[
slen
-1
]
=
' '
;
}
slen
+=
itos
(
e
[
j
]
+
labelorg
,
s
+
slen
);
}
else
slen
=
itos
(
e
[
j
]
+
labelorg
,
s
);
if
(
linelength
>
0
&&
curlen
+
slen
+
1
>
linelength
)
{
putstring
(
f
,
"
\n
"
);
curlen
=
2
;
}
PUTC
(
' '
,
f
);
putstring
(
f
,
s
);
curlen
+=
slen
+
1
;
}
putstring
(
f
,
";
\n
"
);
}
}
/*****************************************************************************
* *
* putmapping(f,lab1,org1,lab2,org2,linelength,n) writes n pairs *
* (lab1[i]+org1)-(lab2[i]+org2) to file f in increasing order of lab1[i]. *
* lab1 and lab2 are assumed to be permutations. At most linelength *
* characters (excluding '\n') are written per line. *
* A value of linelength <= 0 dictates no line breaks at all. *
* *
* FUNCTIONS CALLED: itos(),putstring() *
* *
*****************************************************************************/
void
putmapping
(
FILE
*
f
,
int
*
lab1
,
int
org1
,
int
*
lab2
,
int
org2
,
int
linelength
,
int
n
)
{
int
i
,
curlen
,
slen
;
char
s
[
60
];
#if !MAXN
DYNALLOC1
(
int
,
workperm
,
workperm_sz
,
n
+
2
,
"putmapping"
);
#endif
for
(
i
=
0
;
i
<
n
;
++
i
)
workperm
[
lab1
[
i
]]
=
lab2
[
i
];
curlen
=
0
;
for
(
i
=
0
;
i
<
n
;
++
i
)
{
slen
=
itos
(
i
+
org1
,
s
);
s
[
slen
++
]
=
'-'
;
slen
+=
itos
(
workperm
[
i
]
+
org2
,
&
s
[
slen
]);
if
(
linelength
>
0
&&
curlen
+
slen
+
1
>
linelength
)
{
putstring
(
f
,
"
\n
"
);
curlen
=
2
;
}
PUTC
(
' '
,
f
);
putstring
(
f
,
s
);
curlen
+=
slen
+
1
;
}
PUTC
(
'\n'
,
f
);
}
/*****************************************************************************
* *
* putorbits(f,orbits,linelength,n) writes the orbits to f as lists *
* of integers separated by semicolons. No more than linelength characters *
* (excluding '\n') are written per line. *
* A value of linelength <= 0 dictates no line breaks at all. *
* labelorg is used. *
* *
* FUNCTIONS CALLED: itos(),putset() *
* *
*****************************************************************************/
void
putorbits
(
FILE
*
f
,
int
*
orbits
,
int
linelength
,
int
n
)
{
int
i
,
j
;
int
m
,
curlen
,
sz
,
slen
;
char
s
[
20
];
m
=
SETWORDSNEEDED
(
n
);
#if !MAXN
DYNALLOC1
(
int
,
workperm
,
workperm_sz
,
n
+
2
,
"putorbits"
);
DYNALLOC1
(
set
,
workset
,
workset_sz
,
m
,
"putorbits"
);
#endif
for
(
i
=
n
;
--
i
>=
0
;)
workperm
[
i
]
=
0
;
for
(
i
=
n
;
--
i
>=
0
;)
if
((
j
=
orbits
[
i
])
<
i
)
{
workperm
[
i
]
=
workperm
[
j
];
workperm
[
j
]
=
i
;
}
curlen
=
0
;
for
(
i
=
0
;
i
<
n
;
++
i
)
if
(
orbits
[
i
]
==
i
)
{
sz
=
0
;
EMPTYSET
(
workset
,
m
);
j
=
i
;
do
{
ADDELEMENT
(
workset
,
j
);
j
=
workperm
[
j
];
++
sz
;
}
while
(
j
>
0
);
putset
(
f
,
workset
,
&
curlen
,
linelength
-1
,
m
,
TRUE
);
if
(
sz
>
1
)
{
s
[
0
]
=
' '
;
s
[
1
]
=
'('
;
slen
=
2
+
itos
(
sz
,
s
+
2
);
s
[
slen
++
]
=
')'
;
s
[
slen
]
=
'\0'
;
if
(
linelength
>
0
&&
curlen
+
slen
+
1
>=
linelength
)
{
fprintf
(
f
,
"
\n
"
);
curlen
=
3
;
}
fprintf
(
f
,
"%s"
,
s
);
curlen
+=
slen
;
}
PUTC
(
';'
,
f
);
++
curlen
;
}
PUTC
(
'\n'
,
f
);
}
/*****************************************************************************
* *
* putorbitsplus(f,orbits,linelength,n) is the same as *
* putorbits(f,orbits,linelength,n) except that the first element of each *
* orbit is written bold. This only works if output is to a device that *
* interprets ANSI controls. *
* *
* FUNCTIONS CALLED: itos(),putset() *
* *
*****************************************************************************/
void
putorbitsplus
(
FILE
*
f
,
int
*
orbits
,
int
linelength
,
int
n
)
{
int
i
,
j
;
int
m
,
curlen
,
sz
,
slen
;
char
s
[
20
];
m
=
SETWORDSNEEDED
(
n
);
#if !MAXN
DYNALLOC1
(
int
,
workperm
,
workperm_sz
,
n
+
2
,
"putorbits"
);
DYNALLOC1
(
set
,
workset
,
workset_sz
,
m
,
"putorbits"
);
#endif
for
(
i
=
n
;
--
i
>=
0
;)
workperm
[
i
]
=
0
;
for
(
i
=
n
;
--
i
>=
0
;)
if
((
j
=
orbits
[
i
])
<
i
)
{
workperm
[
i
]
=
workperm
[
j
];
workperm
[
j
]
=
i
;
}
curlen
=
0
;
for
(
i
=
0
;
i
<
n
;
++
i
)
if
(
orbits
[
i
]
==
i
)
{
sz
=
0
;
EMPTYSET
(
workset
,
m
);
j
=
i
;
do
{
ADDELEMENT
(
workset
,
j
);
j
=
workperm
[
j
];
++
sz
;
}
while
(
j
>
0
);
putset_firstbold
(
f
,
workset
,
&
curlen
,
linelength
-1
,
m
,
TRUE
);
if
(
sz
>
1
)
{
s
[
0
]
=
' '
;
s
[
1
]
=
'('
;
slen
=
2
+
itos
(
sz
,
s
+
2
);
s
[
slen
++
]
=
')'
;
s
[
slen
]
=
'\0'
;
if
(
linelength
>
0
&&
curlen
+
slen
+
1
>=
linelength
)
{
fprintf
(
f
,
"
\n
"
);
curlen
=
3
;
}
fprintf
(
f
,
"%s"
,
s
);
curlen
+=
slen
;
}
PUTC
(
';'
,
f
);
++
curlen
;
}
PUTC
(
'\n'
,
f
);
}
/*****************************************************************************
* *
* putquotient(f,g,lab,ptn,level,linelength,m,n) writes the quotient matrix *
* of g defined by the partition at the given level. Precisely, for each *
* cell W, it writes the number w of the least vertex in W, then the size *
* of W, then the number of times w is joined FROM each cell. A complete *
* join is written as "*", while an empty join is written as "-". No more *
* than linelength characters (excluding '\n') are written per line unless *
* linelength is very small. A value of linelength <= 0 dictates no line *
* breaks at all. labelorg is used. *
* *
* FUNCTIONS CALLED: itos() *
* *
*****************************************************************************/
void
putquotient
(
FILE
*
f
,
graph
*
g
,
int
*
lab
,
int
*
ptn
,
int
level
,
int
linelength
,
int
m
,
int
n
)
{
int
i
;
char
s
[
50
];
int
ic
,
curlen
,
v
,
w
,
cell1
,
cell2
,
numcells
,
jc
,
csize
,
k
;
set
*
gw
;
#if !MAXN
DYNALLOC1
(
int
,
workperm
,
workperm_sz
,
n
+
2
,
"putquotient"
);
DYNALLOC1
(
set
,
workset
,
workset_sz
,
m
,
"putquotient"
);
#endif
numcells
=
0
;
for
(
cell1
=
0
;
cell1
<
n
;
cell1
=
cell2
+
1
)
{
for
(
cell2
=
cell1
;
ptn
[
cell2
]
>
level
;
++
cell2
)
{}
w
=
lab
[
cell1
];
for
(
i
=
cell1
+
1
;
i
<=
cell2
;
++
i
)
if
(
lab
[
i
]
<
w
)
w
=
lab
[
i
];
workperm
[
numcells
++
]
=
w
;
}
for
(
ic
=
cell1
=
0
;
ic
<
numcells
;
++
ic
,
cell1
=
cell2
+
1
)
{
for
(
cell2
=
cell1
;
ptn
[
cell2
]
>
level
;
++
cell2
)
{}
EMPTYSET
(
workset
,
M
);
for
(
i
=
cell1
;
i
<=
cell2
;
++
i
)
ADDELEMENT
(
workset
,
lab
[
i
]);
v
=
workperm
[
ic
];
csize
=
cell2
-
cell1
+
1
;
if
(
v
+
labelorg
<
10
)
{
s
[
0
]
=
' '
;
curlen
=
1
;
}
else
curlen
=
0
;
curlen
+=
itos
(
v
+
labelorg
,
&
s
[
curlen
]);
s
[
curlen
++
]
=
'['
;
curlen
+=
itos
(
csize
,
&
s
[
curlen
]);
fprintf
(
f
,
"%s"
,
s
);
if
(
csize
<
10
)
{
fprintf
(
f
,
"] :"
);
curlen
+=
4
;
}
else
{
fprintf
(
f
,
"] :"
);
curlen
+=
3
;
}
for
(
jc
=
0
;
jc
<
numcells
;
++
jc
)
{
w
=
workperm
[
jc
];
gw
=
GRAPHROW
(
g
,
w
,
m
);
k
=
setinter
(
gw
,
workset
,
M
);
if
(
k
==
0
||
k
==
csize
)
{
if
(
linelength
>
0
&&
curlen
+
2
>
linelength
)
{
fprintf
(
f
,
"
\n
"
);
curlen
=
4
;
}
if
(
k
==
0
)
fprintf
(
f
,
" -"
);
else
fprintf
(
f
,
" *"
);
curlen
+=
2
;
}
else
{
i
=
itos
(
k
,
s
);
if
(
linelength
>
0
&&
curlen
+
i
+
1
>
linelength
)
{
fprintf
(
f
,
"
\n
"
);
curlen
=
4
;
}
fprintf
(
f
,
" %s"
,
s
);
curlen
+=
i
+
1
;
}
}
fprintf
(
f
,
"
\n
"
);
}
}
/*****************************************************************************
* *
* putquotient_sg(f,g,lab,ptn,level,linelength) writes the quotient matrix *
* of g defined by the partition at the given level. Precisely, for each *
* cell W, it writes the number w of the least vertex in W, then the size *
* of W, then the number of times w is joined FROM each cell. A complete *
* join is written as "*", while an empty join is written as "-". No more *
* than linelength characters (excluding '\n') are written per line unless *
* linelength is very small. A value of linelength <= 0 dictates no line *
* breaks at all. labelorg is used. *
* *
* Weughts are ignored. *
* *
*****************************************************************************/
void
putquotient_sg
(
FILE
*
f
,
sparsegraph
*
g
,
int
*
lab
,
int
*
ptn
,
int
level
,
int
linelength
)
{
int
i
,
m
,
n
;
char
s
[
50
];
int
ic
,
curlen
,
v
,
w
,
cell1
,
cell2
,
numcells
,
jc
,
csize
,
k
;
int
*
dd
,
*
ee
;
size_t
*
vv
,
j
;
n
=
g
->
nv
;
m
=
SETWORDSNEEDED
(
n
);
SG_VDE
(
g
,
vv
,
dd
,
ee
);
#if !MAXN
DYNALLOC1
(
int
,
workperm
,
workperm_sz
,
n
+
2
,
"putquotient"
);
DYNALLOC1
(
set
,
workset
,
workset_sz
,
m
,
"putquotient"
);
#endif
numcells
=
0
;
for
(
cell1
=
0
;
cell1
<
n
;
cell1
=
cell2
+
1
)
{
for
(
cell2
=
cell1
;
ptn
[
cell2
]
>
level
;
++
cell2
)
{}
w
=
lab
[
cell1
];
for
(
i
=
cell1
+
1
;
i
<=
cell2
;
++
i
)
if
(
lab
[
i
]
<
w
)
w
=
lab
[
i
];
workperm
[
numcells
++
]
=
w
;
}
for
(
ic
=
cell1
=
0
;
ic
<
numcells
;
++
ic
,
cell1
=
cell2
+
1
)
{
for
(
cell2
=
cell1
;
ptn
[
cell2
]
>
level
;
++
cell2
)
{}
EMPTYSET
(
workset
,
M
);
for
(
i
=
cell1
;
i
<=
cell2
;
++
i
)
ADDELEMENT
(
workset
,
lab
[
i
]);
v
=
workperm
[
ic
];
csize
=
cell2
-
cell1
+
1
;
if
(
v
+
labelorg
<
10
)
{
s
[
0
]
=
' '
;
curlen
=
1
;
}
else
curlen
=
0
;
curlen
+=
itos
(
v
+
labelorg
,
&
s
[
curlen
]);
s
[
curlen
++
]
=
'['
;
curlen
+=
itos
(
csize
,
&
s
[
curlen
]);
fprintf
(
f
,
"%s"
,
s
);
if
(
csize
<
10
)
{
fprintf
(
f
,
"] :"
);
curlen
+=
4
;
}
else
{
fprintf
(
f
,
"] :"
);
curlen
+=
3
;
}
for
(
jc
=
0
;
jc
<
numcells
;
++
jc
)
{
w
=
workperm
[
jc
];
k
=
0
;
for
(
j
=
vv
[
w
];
j
<
vv
[
w
]
+
dd
[
w
];
++
j
)
if
(
ISELEMENT
(
workset
,
ee
[
j
]))
++
k
;
if
(
k
==
0
||
k
==
csize
)
{
if
(
linelength
>
0
&&
curlen
+
2
>
linelength
)
{
fprintf
(
f
,
"
\n
"
);
curlen
=
4
;
}
if
(
k
==
0
)
fprintf
(
f
,
" -"
);
else
fprintf
(
f
,
" *"
);
curlen
+=
2
;
}
else
{
i
=
itos
(
k
,
s
);
if
(
linelength
>
0
&&
curlen
+
i
+
1
>
linelength
)
{
fprintf
(
f
,
"
\n
"
);
curlen
=
4
;
}
fprintf
(
f
,
" %s"
,
s
);
curlen
+=
i
+
1
;
}
}
fprintf
(
f
,
"
\n
"
);
}
}
/*****************************************************************************
* *
* putptn(f,lab,ptn,level,linelength,n) writes the partition at the given *
* level as sorted lists of integers separated by semicolons. No more than *
* linelength characters (excluding '\n') are written per line. *
* A value of linelength <= 0 dictates no line breaks at all. *
* labelorg is used. *
* *
*****************************************************************************/
void
putptn
(
FILE
*
f
,
int
*
lab
,
int
*
ptn
,
int
level
,
int
linelength
,
int
n
)
{
int
i
;
int
curlen
,
m
;
m
=
SETWORDSNEEDED
(
n
);
#if !MAXN
DYNALLOC1
(
set
,
workset
,
workset_sz
,
m
,
"putptn"
);
#endif
PUTC
(
'['
,
f
);
curlen
=
1
;
i
=
0
;
while
(
i
<
n
)
{
EMPTYSET
(
workset
,
m
);
while
(
TRUE
)
{
ADDELEMENT
(
workset
,
lab
[
i
]);
if
(
ptn
[
i
]
>
level
)
++
i
;
else
break
;
}
putset
(
f
,
workset
,
&
curlen
,
linelength
-2
,
m
,
TRUE
);
if
(
i
<
n
-1
)
{
fprintf
(
f
,
" |"
);
curlen
+=
2
;
}
++
i
;
}
fprintf
(
f
,
" ]
\n
"
);
}
/*****************************************************************************
* *
* putcanon(f,canonlab,canong,linelength,m,n) writes the label canonlab *
* and the graph canong to f, using at most linelength characters *
* (excluding '\n') per line. labelorg is used. *
* A value of linelength <= 0 dictates no line breaks at all. *
* *
*****************************************************************************/
void
putcanon
(
FILE
*
f
,
int
*
canonlab
,
graph
*
canong
,
int
linelength
,
int
m
,
int
n
)
{
int
i
;
#if !MAXN
DYNALLOC1
(
int
,
workperm
,
workperm_sz
,
n
+
2
,
"putcanon"
);
#endif
for
(
i
=
0
;
i
<
n
;
++
i
)
workperm
[
i
]
=
canonlab
[
i
];
writeperm
(
f
,
workperm
,
TRUE
,
linelength
,
n
);
putgraph
(
f
,
canong
,
linelength
,
m
,
n
);
}
/*****************************************************************************
* *
* putcanon_sg(f,canonlab,canong,linelength) writes the label canonlab *
* and the graph canong to f, using at most linelength characters *
* (excluding '\n') per line. labelorg is used. *
* A value of linelength <= 0 dictates no line breaks at all. *
* *
*****************************************************************************/
void
putcanon_sg
(
FILE
*
f
,
int
*
canonlab
,
sparsegraph
*
canong
,
int
linelength
)
{
int
i
,
n
;
n
=
canong
->
nv
;
#if !MAXN
DYNALLOC1
(
int
,
workperm
,
workperm_sz
,
n
+
2
,
"putcanon"
);
#endif
for
(
i
=
0
;
i
<
n
;
++
i
)
workperm
[
i
]
=
canonlab
[
i
];
writeperm
(
f
,
workperm
,
TRUE
,
linelength
,
n
);
putgraph_sg
(
f
,
canong
,
linelength
);
}
/*****************************************************************************
* *
* readptn(f,lab,ptn,&numcells,prompt,n) reads a partition from f *
* and establishes it in (lab,ptn). *
* The format can be just a number, which is fixed alone, or an arbitrary *
* partition [...|...|...]. Ranges x:y can be used. *
* labelorg is used. *
* *
*****************************************************************************/
void
readptn
(
FILE
*
f
,
int
*
lab
,
int
*
ptn
,
int
*
numcells
,
boolean
prompt
,
int
n
)
{
int
i
,
j
;
int
c
,
v1
,
v2
,
m
;
m
=
SETWORDSNEEDED
(
n
);
#if !MAXN
DYNALLOC1
(
set
,
workset
,
workset_sz
,
m
,
"readptn"
);
#endif
GETNW
(
c
,
f
);
if
(
c
==
'='
)
GETNW
(
c
,
f
);
if
(
ISDIGIT
(
c
))
{
ungetc
(
c
,
f
);
readinteger
(
f
,
&
v1
);
v1
-=
labelorg
;
if
(
v1
>=
0
&&
v1
<
n
)
fixit
(
lab
,
ptn
,
numcells
,
v1
,
n
);
else
{
fprintf
(
ERRFILE
,
"vertex out of range (%d), fixing nothing
\n\n
"
,
v1
+
labelorg
);
unitptn
(
lab
,
ptn
,
numcells
,
n
);
}
return
;
}
if
(
c
!=
'['
)
{
ungetc
(
c
,
f
);
fprintf
(
ERRFILE
,
"illegal partition, fixing nothing
\n\n
"
);
unitptn
(
lab
,
ptn
,
numcells
,
n
);
return
;
}
EMPTYSET
(
workset
,
m
);
*
numcells
=
0
;
for
(
i
=
0
;
i
<
n
;
++
i
)
ptn
[
i
]
=
NAUTY_INFINITY
;
i
=
0
;
j
=
-1
;
while
(
TRUE
)
{
GETNWC
(
c
,
f
);
if
(
ISDIGIT
(
c
))
{
ungetc
(
c
,
f
);
readinteger
(
f
,
&
v1
);
v1
-=
labelorg
;
GETNWC
(
c
,
f
);
if
(
c
==
':'
)
if
(
!
readinteger
(
f
,
&
v2
))
{
fprintf
(
ERRFILE
,
"unfinished range
\n\n
"
);
v2
=
v1
;
}
else
v2
-=
labelorg
;
else
{
ungetc
(
c
,
f
);
v2
=
v1
;
}
while
(
v1
<=
v2
)
{
if
(
v1
<
0
||
v1
>=
n
||
ISELEMENT
(
workset
,
v1
))
fprintf
(
ERRFILE
,
"illegal or repeated number : %d
\n\n
"
,
v1
+
labelorg
);
else
{
ADDELEMENT
(
workset
,
v1
);
lab
[
++
j
]
=
v1
;
}
++
v1
;
}
}
else
if
(
c
==
'|'
||
c
==
']'
||
c
==
EOF
)
{
if
(
j
>=
i
)
{
++*
numcells
;
ptn
[
j
]
=
0
;
}
if
(
c
==
'|'
)
i
=
j
+
1
;
else
if
(
j
==
n
-
1
)
return
;
else
{
i
=
j
+
1
;
++*
numcells
;
for
(
j
=
0
;
j
<
n
;
++
j
)
if
(
!
ISELEMENT
(
workset
,
j
))
lab
[
i
++
]
=
j
;
ptn
[
n
-1
]
=
0
;
return
;
}
}
else
if
(
c
==
'\n'
)
{
if
(
prompt
)
fprintf
(
PROMPTFILE
,
"] "
);
}
else
fprintf
(
ERRFILE
,
"illegal character '%c' in partition
\n\n
"
,
c
);
}
}
/*****************************************************************************
* *
* unitptn(lab,ptn,&numcells,n) establishes the partition with one cell. *
* *
*****************************************************************************/
void
unitptn
(
int
*
lab
,
int
*
ptn
,
int
*
numcells
,
int
n
)
{
int
i
;
for
(
i
=
0
;
i
<
n
;
++
i
)
{
lab
[
i
]
=
i
;
ptn
[
i
]
=
NAUTY_INFINITY
;
}
ptn
[
n
-1
]
=
0
;
*
numcells
=
1
;
}
/*****************************************************************************
* *
* individualise(lab,ptn,level,v,&pos,&numcells,n) individualises vertex v. *
* numcells is updated and the position of the possibly-new singleton is *
* returned in pos. *
* *
*****************************************************************************/
void
individualise
(
int
*
lab
,
int
*
ptn
,
int
level
,
int
v
,
int
*
pos
,
int
*
numcells
,
int
n
)
{
int
i
,
j
;
for
(
i
=
0
;
i
<
n
;
++
i
)
if
(
lab
[
i
]
==
v
)
break
;
for
(
j
=
i
;
j
>
0
&&
ptn
[
j
-1
]
>
level
;
--
j
)
{};
*
pos
=
j
;
if
(
ptn
[
j
]
<=
level
)
return
;
/* individual already */
lab
[
i
]
=
lab
[
j
];
lab
[
j
]
=
v
;
ptn
[
j
]
=
level
;
++*
numcells
;
}
/*****************************************************************************
* *
* cellstarts(ptn,level,cell,m,n) sets the set cell to contain the indices *
* of the starts in ptn of the partition at level level. *
* *
*****************************************************************************/
void
cellstarts
(
int
*
ptn
,
int
level
,
set
*
cell
,
int
m
,
int
n
)
{
int
i
;
EMPTYSET
(
cell
,
m
);
i
=
0
;
while
(
i
<
n
)
{
ADDELEMENT
(
cell
,
i
);
while
(
ptn
[
i
]
>
level
)
++
i
;
++
i
;
}
}
/*****************************************************************************
* *
* fixit(lab,ptn,&numcells,fixedvertex,n) establishes the partition *
* with one cell {fixedvertex} and all the other vertices (if any) in *
* another cell. *
* *
*****************************************************************************/
void
fixit
(
int
*
lab
,
int
*
ptn
,
int
*
numcells
,
int
fixedvertex
,
int
n
)
{
int
i
;
for
(
i
=
1
;
i
<
n
;
++
i
)
{
lab
[
i
]
=
i
;
ptn
[
i
]
=
1
;
}
lab
[
0
]
=
fixedvertex
;
lab
[
fixedvertex
]
=
0
;
ptn
[
0
]
=
0
;
ptn
[
n
-1
]
=
0
;
if
(
n
==
1
)
*
numcells
=
1
;
else
*
numcells
=
2
;
}
/*****************************************************************************
* *
* sethash(s,n,seed,key) is a function whose value depends only on the *
* set s, a long seed, and an integer key. It is intended to be independent *
* of the word size provided long ints have at least 32 bits, and also *
* independent of m. n is the underlying universal set size. *
* 31 bits of seed and 15 bits of key are significant. *
* The result is in 0..2^31-1. *
* *
*****************************************************************************/
long
sethash
(
set
*
s
,
int
n
,
long
seed
,
int
key
)
{
int
i
,
j
,
lsh
,
rsh
;
unsigned
long
l
,
res
,
lshmask
,
salt
;
setword
si
;
lsh
=
key
&
0xF
;
rsh
=
28
-
lsh
;
salt
=
(
key
>>
4
)
&
0x7FFL
;
res
=
seed
&
0x7FFFFFFFUL
;
lshmask
=
(
1UL
<<
lsh
)
-
1
;
j
=
0
;
for
(
i
=
0
;
;
++
i
)
{
si
=
s
[
i
];
l
=
SWCHUNK0
(
si
);
res
=
(((
res
<<
lsh
)
^
((
res
>>
rsh
)
&
lshmask
)
^
l
)
+
salt
)
&
0x7FFFFFFFUL
;
res
=
FUZZ1
(
res
);
if
((
j
+=
16
)
>=
n
)
break
;
#if WORDSIZE > 16
l
=
SWCHUNK1
(
si
);
res
=
(((
res
<<
lsh
)
^
((
res
>>
rsh
)
&
lshmask
)
^
l
)
+
salt
)
&
0x7FFFFFFFUL
;
res
=
FUZZ1
(
res
);
if
((
j
+=
16
)
>=
n
)
break
;
#if WORDSIZE == 64
l
=
SWCHUNK2
(
si
);
res
=
(((
res
<<
lsh
)
^
((
res
>>
rsh
)
&
lshmask
)
^
l
)
+
salt
)
&
0x7FFFFFFFUL
;
res
=
FUZZ1
(
res
);
if
((
j
+=
16
)
>=
n
)
break
;
l
=
SWCHUNK3
(
si
);
res
=
(((
res
<<
lsh
)
^
((
res
>>
rsh
)
&
lshmask
)
^
l
)
+
salt
)
&
0x7FFFFFFFUL
;
res
=
FUZZ1
(
res
);
if
((
j
+=
16
)
>=
n
)
break
;
#endif
#endif
}
return
res
;
}
/*****************************************************************************
* *
* listhash(x,nx,key) is a function whose value depends on the SET of values *
* in the first 'nx' entries of the array 'x', and the value of key. *
* Machine-independent if long ints have at least 32 bits, otherwise not. *
* The result is in 0..2^31-1. *
* *
*****************************************************************************/
long
listhash
(
int
*
x
,
int
nx
,
long
key
)
{
unsigned
long
lkey
,
val
,
accum
;
int
i
;
lkey
=
(
unsigned
long
)
key
&
0x7FFFFFFFUL
;
accum
=
nx
;
for
(
i
=
0
;
i
<
nx
;
++
i
)
{
val
=
(
unsigned
long
)
x
[
i
]
&
0x7FFFFFFFUL
;
val
=
(
val
+
lkey
)
&
0x7FFFFFFFUL
;
accum
+=
FUZZ1
(
val
);
}
return
accum
&
0x7FFFFFFFUL
;
}
/*****************************************************************************
* *
* hashgraph_sg(sg,key) is a function whose value depends on the sparse *
* graph or digraph sg. *
* Machine-independent if long ints have at least 32 bits, otherwise not. *
* The result is in 0..2^31-1. *
* *
*****************************************************************************/
long
hashgraph_sg
(
sparsegraph
*
sg
,
long
key
)
{
int
n
,
i
;
int
*
d
,
*
e
;
size_t
*
v
;
unsigned
long
val
,
accum
;
CHECK_SWG
(
sg
,
"hashgraph_sg"
);
accum
=
n
=
sg
->
nv
;
SG_VDE
(
sg
,
v
,
d
,
e
);
for
(
i
=
0
;
i
<
n
;
++
i
)
if
(
d
[
i
]
==
0
)
accum
+=
FUZZ1
(
i
);
else
{
accum
=
(
accum
>>
7
)
|
((
accum
<<
24
)
&
0x7FFFFFFFUL
);
val
=
listhash
(
e
+
v
[
i
],
d
[
i
],
key
);
val
=
(
val
+
i
)
&
0x7FFFFFFFUL
;
accum
+=
FUZZ2
(
val
);
}
return
(
long
)(
accum
&
0x7FFFFFFFUL
);
}
/*****************************************************************************
* *
* hashgraph(g,m,n,key) is a function whose value depends on the *
* graph or digraph sg. *
* Machine-independent if long ints have at least 32 bits, otherwise not. *
* The result is in 0..2^31-1. *
* *
*****************************************************************************/
long
hashgraph
(
graph
*
g
,
int
m
,
int
n
,
long
key
)
{
int
i
;
set
*
gi
;
unsigned
long
val
,
accum
;
accum
=
n
;
for
(
i
=
0
,
gi
=
g
;
i
<
n
;
++
i
,
gi
+=
m
)
{
accum
=
(
accum
>>
12
)
|
((
accum
<<
19
)
&
0x7FFFFFFFUL
);
val
=
sethash
(
gi
,
n
,
key
,(
key
&
0xFL
)
+
i
);
val
=
(
val
+
i
)
&
0x7FFFFFFFUL
;
accum
+=
FUZZ2
(
val
);
}
return
(
long
)(
accum
&
0x7FFFFFFFUL
);
}
/*****************************************************************************
* *
* hash(setarray,length,key) is a function whose value depends only on the *
* first 'length' entries of the array 'setarray', and the value of key. *
* key should be in the range 1..31 and preferably odd. *
* This works best if long ints have at least 32 bits, but it's valid anyway.*
* Not machine-indpendent! Use sethash() in preference. *
* *
*****************************************************************************/
long
hash
(
set
*
setarray
,
long
length
,
int
key
)
{
long
code
;
set
*
sptr
;
code
=
length
;
sptr
=
setarray
+
length
;
while
(
--
sptr
>=
setarray
)
code
=
(
code
<<
key
)
^
((
code
>>
(
32
-
key
))
+
*
sptr
);
return
code
;
}
/*****************************************************************************
* *
* readperm is like readvperm without the last argument. It is provided *
* only for backward compatibility. *
* *
*****************************************************************************/
void
readperm
(
FILE
*
f
,
int
*
perm
,
boolean
prompt
,
int
n
)
{
int
nv
;
readvperm
(
f
,
perm
,
prompt
,
n
,
&
nv
);
}
/*****************************************************************************
* *
* readvperm(f,perm,prompt,n,nv) reads a permutation of order n from *
* f, terminated by a semicolon. Any repeated or illegal numbers or *
* characters are reported then ignored. Missing numbers are filled in *
* in numerical order. A prompt is issued for each line if prompt!=FALSE. *
* labelorg is used. *nv is set equal to the number of numbers actually *
* given. Ranges like v1:v2 are allowed. *
* *
*****************************************************************************/
void
readvperm
(
FILE
*
f
,
int
*
perm
,
boolean
prompt
,
int
n
,
int
*
nv
)
{
int
i
;
int
m
,
c
,
v1
,
v2
;
m
=
SETWORDSNEEDED
(
n
);
#if !MAXN
DYNALLOC1
(
set
,
workset
,
workset_sz
,
m
,
"readperm"
);
#endif
EMPTYSET
(
workset
,
m
);
i
=
0
;
while
(
TRUE
)
{
GETNWC
(
c
,
f
);
if
(
c
==
';'
||
c
==
EOF
)
break
;
if
(
ISDIGIT
(
c
))
{
ungetc
(
c
,
f
);
readinteger
(
f
,
&
v1
);
v1
-=
labelorg
;
GETNWC
(
c
,
f
);
if
(
c
==
':'
)
if
(
!
readinteger
(
f
,
&
v2
))
{
fprintf
(
ERRFILE
,
"unfinished range
\n\n
"
);
v2
=
v1
;
}
else
v2
-=
labelorg
;
else
{
ungetc
(
c
,
f
);
v2
=
v1
;
}
if
(
v1
<
0
||
v1
>=
n
||
v2
>=
n
||
v1
>
v2
)
{
if
(
v1
<
v2
)
fprintf
(
ERRFILE
,
"illegal range in permutation : %d:%d
\n\n
"
,
v1
+
labelorg
,
v2
+
labelorg
);
else
fprintf
(
ERRFILE
,
"illegal number in permutation : %d
\n\n
"
,
v1
+
labelorg
);
}
else
for
(;
v1
<=
v2
;
++
v1
)
{
if
(
!
ISELEMENT
(
workset
,
v1
))
{
perm
[
i
++
]
=
v1
;
ADDELEMENT
(
workset
,
v1
);
}
else
fprintf
(
ERRFILE
,
"repeated number in permutation : %d
\n\n
"
,
v1
+
labelorg
);
}
}
else
{
if
(
c
==
'\n'
&&
prompt
)
fprintf
(
PROMPTFILE
,
"+ "
);
if
(
c
!=
'\n'
)
fprintf
(
ERRFILE
,
"bad character '%c' in permutation
\n\n
"
,
(
char
)
c
);
}
}
*
nv
=
i
;
for
(
v1
=
0
;
v1
<
n
;
++
v1
)
if
(
!
ISELEMENT
(
workset
,
v1
))
perm
[
i
++
]
=
v1
;
}
/*****************************************************************************
* *
* ranperm(perm,n) creates a random permutation in perm. *
* *
*****************************************************************************/
void
ranperm
(
int
*
perm
,
int
n
)
{
int
i
,
j
,
t
;
for
(
i
=
n
;
--
i
>=
0
;
)
perm
[
i
]
=
i
;
for
(
i
=
n
;
--
i
>
0
;
)
{
j
=
KRAN
(
i
+
1
);
t
=
perm
[
i
];
perm
[
i
]
=
perm
[
j
];
perm
[
j
]
=
t
;
}
}
/*****************************************************************************
* *
* relabel(g,perm,lab,workg,m,n) replaces g by g^perm, using workg as *
* scratch space. If lab!=NULL, it is taken as a labelling vector and *
* also permuted. *
* *
*****************************************************************************/
void
relabel
(
graph
*
g
,
int
*
lab
,
int
*
perm
,
graph
*
workg
,
int
m
,
int
n
)
{
long
li
;
int
i
;
for
(
li
=
(
long
)
M
*
(
long
)
n
;
--
li
>=
0
;)
workg
[
li
]
=
g
[
li
];
updatecan
(
workg
,
g
,
perm
,
0
,
M
,
n
);
if
(
lab
!=
NULL
)
{
#if !MAXN
DYNALLOC1
(
int
,
workperm
,
workperm_sz
,
n
+
2
,
"relabel"
);
#endif
for
(
i
=
0
;
i
<
n
;
++
i
)
workperm
[
perm
[
i
]]
=
i
;
for
(
i
=
0
;
i
<
n
;
++
i
)
lab
[
i
]
=
workperm
[
lab
[
i
]];
}
}
/*****************************************************************************
* *
* relabel_sg(g,perm,lab,workg,m,n) replaces g by g^perm, using workg as *
* scratch space. If lab!=NULL, it is taken as a labelling vector and *
* also permuted. *
* *
*****************************************************************************/
void
relabel_sg
(
sparsegraph
*
sg
,
int
*
lab
,
int
*
perm
,
sparsegraph
*
workg
)
{
int
i
,
n
;
sparsegraph
*
tempsg
;
sparsegraph
tmp
;
n
=
sg
->
nv
;
if
(
workg
)
{
tempsg
=
copy_sg
(
sg
,
workg
);
updatecan_sg
((
graph
*
)
tempsg
,(
graph
*
)
sg
,
perm
,
0
,
SETWORDSNEEDED
(
n
),
n
);
}
else
{
SG_INIT
(
tmp
);
tempsg
=
copy_sg
(
sg
,
&
tmp
);
updatecan_sg
((
graph
*
)
tempsg
,(
graph
*
)
sg
,
perm
,
0
,
SETWORDSNEEDED
(
n
),
n
);
SG_FREE
(
tmp
);
}
if
(
lab
!=
NULL
)
{
#if !MAXN
DYNALLOC1
(
int
,
workperm
,
workperm_sz
,
n
+
2
,
"relabel_sg"
);
#endif
for
(
i
=
0
;
i
<
n
;
++
i
)
workperm
[
perm
[
i
]]
=
i
;
for
(
i
=
0
;
i
<
n
;
++
i
)
lab
[
i
]
=
workperm
[
lab
[
i
]];
}
}
/*****************************************************************************
* *
* sublabel(g,perm,nperm,workg,m,n) replaces g by g^perm, using workg as *
* scratch space. perm is a partial vector, of length nperm, where it is *
* known that the elements of perm are distinct. *
* *
*****************************************************************************/
void
sublabel
(
graph
*
g
,
int
*
perm
,
int
nperm
,
graph
*
workg
,
int
m
,
int
n
)
{
long
li
;
int
i
,
j
,
k
;
int
newm
;
set
*
gi
,
*
wgi
;
for
(
li
=
(
long
)
m
*
(
long
)
n
;
--
li
>=
0
;)
workg
[
li
]
=
g
[
li
];
newm
=
SETWORDSNEEDED
(
nperm
);
for
(
li
=
(
long
)
newm
*
(
long
)
nperm
;
--
li
>=
0
;)
g
[
li
]
=
0
;
for
(
i
=
0
,
gi
=
(
set
*
)
g
;
i
<
nperm
;
++
i
,
gi
+=
newm
)
{
wgi
=
GRAPHROW
(
workg
,
perm
[
i
],
m
);
for
(
j
=
0
;
j
<
nperm
;
++
j
)
{
k
=
perm
[
j
];
if
(
ISELEMENT
(
wgi
,
k
))
ADDELEMENT
(
gi
,
j
);
}
}
}
/*****************************************************************************
* *
* countcells(ptn,level,n) finds the number of elements of ptn[0..n-1] *
* that are <= level. *
* *
*****************************************************************************/
int
countcells
(
int
*
ptn
,
int
level
,
int
n
)
{
int
i
,
cnt
;
cnt
=
0
;
for
(
i
=
0
;
i
<
n
;
++
i
)
if
(
ptn
[
i
]
<=
level
)
++
cnt
;
return
cnt
;
}
/*****************************************************************************
* *
* subpartion(lab,ptn,n,perm,nperm) replaces the partition (lab,ptn) of *
* 0..n-1 by the induced partition of 0..nperm-1, using the partial *
* ordering of 0..n-1 given in perm[0..nperm-1]. *
* Return the new number of cells. *
* *
*****************************************************************************/
#define DEB(str,x) fprintf(stderr,"%s=%d\n",str,x);
int
subpartition
(
int
*
lab
,
int
*
ptn
,
int
n
,
int
*
perm
,
int
nperm
)
{
int
i
,
j
;
#if !MAXN
DYNALLOC1
(
int
,
workperm
,
workperm_sz
,
n
+
2
,
"subpartition"
);
#endif
for
(
i
=
0
;
i
<
n
;
++
i
)
workperm
[
i
]
=
-1
;
for
(
i
=
0
;
i
<
nperm
;
++
i
)
workperm
[
perm
[
i
]]
=
i
;
j
=
-1
;
for
(
i
=
0
;
i
<
n
;
++
i
)
{
if
(
workperm
[
lab
[
i
]]
>=
0
)
{
++
j
;
lab
[
j
]
=
workperm
[
lab
[
i
]];
ptn
[
j
]
=
ptn
[
i
];
}
else
if
(
j
>=
0
&&
ptn
[
i
]
<
ptn
[
j
])
ptn
[
j
]
=
ptn
[
i
];
}
return
countcells
(
ptn
,
0
,
nperm
);
}
/*****************************************************************************
* *
* sublabel_sg(sg,perm,nperm,workg) replaces g by g^perm, using workg as *
* scratch space. perm is a partial vector, of length nperm, where it is *
* known that the elements of perm are distinct. *
* *
*****************************************************************************/
void
sublabel_sg
(
sparsegraph
*
sg
,
int
*
perm
,
int
nperm
,
sparsegraph
*
workg
)
{
int
i
,
j
,
k
,
n
;
size_t
newnde
,
kk
;
sparsegraph
*
tempsg
;
sparsegraph
tmp
;
int
*
d
,
*
e
;
int
*
dd
,
*
ee
;
size_t
*
v
,
*
vv
;
CHECK_SWG
(
sg
,
"sublabel_sg"
);
n
=
sg
->
nv
;
#if !MAXN
DYNALLOC1
(
int
,
workperm
,
workperm_sz
,
n
+
2
,
"relabel_sg"
);
#endif
for
(
i
=
0
;
i
<
n
;
++
i
)
workperm
[
i
]
=
-1
;
for
(
i
=
0
;
i
<
nperm
;
++
i
)
workperm
[
perm
[
i
]]
=
i
;
newnde
=
0
;
SG_VDE
(
sg
,
v
,
d
,
e
);
for
(
i
=
0
;
i
<
nperm
;
++
i
)
{
j
=
perm
[
i
];
for
(
k
=
0
;
k
<
d
[
j
];
++
k
)
if
(
workperm
[
e
[
v
[
j
]
+
k
]]
>=
0
)
++
newnde
;
}
if
(
workg
)
tempsg
=
workg
;
else
{
SG_INIT
(
tmp
);
tempsg
=
&
tmp
;
}
SG_ALLOC
(
*
tempsg
,
nperm
,
newnde
,
"sublabel_sg"
);
SG_VDE
(
tempsg
,
vv
,
dd
,
ee
);
kk
=
0
;
for
(
i
=
0
;
i
<
nperm
;
++
i
)
{
j
=
perm
[
i
];
vv
[
i
]
=
kk
;
dd
[
i
]
=
0
;
for
(
k
=
0
;
k
<
d
[
j
];
++
k
)
if
(
workperm
[
e
[
v
[
j
]
+
k
]]
>=
0
)
{
ee
[
vv
[
i
]
+
dd
[
i
]]
=
workperm
[
e
[
v
[
j
]
+
k
]];
++
dd
[
i
];
}
kk
+=
dd
[
i
];
}
tempsg
->
nv
=
nperm
;
tempsg
->
nde
=
newnde
;
copy_sg
(
tempsg
,
sg
);
if
(
!
workg
)
SG_FREE
(
tmp
);
}
/*****************************************************************************
* *
* copycomment(fin,fout,delimiter) copies fin to fout until either EOF or *
* the character 'delimiter' is read. The delimiter itself isn't written. *
* Escape sequences \n,\t,\b,\r,\f,\\,\',\",\\n are recognised. Otherwise, *
* '\' is ignored. *
* *
*****************************************************************************/
void
copycomment
(
FILE
*
fin
,
FILE
*
fout
,
int
delimiter
)
{
int
c
,
backslash
;
backslash
=
FALSE
;
while
((
c
=
getc
(
fin
))
!=
EOF
&&
(
c
!=
delimiter
||
backslash
))
if
(
backslash
)
{
switch
(
c
)
{
case
'\n'
:
break
;
case
'n'
:
PUTC
(
'\n'
,
fout
);
break
;
case
't'
:
PUTC
(
'\t'
,
fout
);
break
;
case
'b'
:
PUTC
(
'\b'
,
fout
);
break
;
case
'r'
:
PUTC
(
'\r'
,
fout
);
break
;
case
'f'
:
PUTC
(
'\f'
,
fout
);
break
;
case
'\\'
:
PUTC
(
'\\'
,
fout
);
break
;
case
'\''
:
PUTC
(
'\''
,
fout
);
break
;
case
'"'
:
PUTC
(
'"'
,
fout
);
break
;
default
:
PUTC
(
c
,
fout
);
}
backslash
=
FALSE
;
}
else
if
(
c
==
'\\'
)
backslash
=
TRUE
;
else
PUTC
(
c
,
fout
);
}
/*****************************************************************************
* *
* converse_sg(g1,g2) performs a digraph converse operation on g1, *
* leaving the result in g2. g2 must exist and be initialised. *
* If g1 is an undirected graph, g2 will be the same. *
* *
*****************************************************************************/
void
converse_sg
(
sparsegraph
*
g1
,
sparsegraph
*
g2
)
{
int
*
e1
,
*
d1
,
*
e2
,
*
d2
;
size_t
*
v1
,
*
v2
,
j
;
int
i
,
k
,
n
;
CHECK_SWG
(
g1
,
"converse_sg"
);
n
=
g1
->
nv
;
SG_ALLOC
(
*
g2
,
n
,
g1
->
nde
,
"converse_sg"
);
g2
->
nv
=
n
;
g2
->
nde
=
g1
->
nde
;
DYNFREE
(
g2
->
w
,
g2
->
wlen
);
SG_VDE
(
g1
,
v1
,
d1
,
e1
);
SG_VDE
(
g2
,
v2
,
d2
,
e2
);
for
(
i
=
0
;
i
<
n
;
++
i
)
d2
[
i
]
=
0
;
for
(
i
=
0
;
i
<
n
;
++
i
)
for
(
j
=
v1
[
i
];
j
<
v1
[
i
]
+
d1
[
i
];
++
j
)
++
d2
[
e1
[
j
]];
v2
[
0
]
=
0
;
for
(
i
=
1
;
i
<
n
;
++
i
)
v2
[
i
]
=
v2
[
i
-1
]
+
d2
[
i
-1
];
for
(
i
=
0
;
i
<
n
;
++
i
)
d2
[
i
]
=
0
;
for
(
i
=
0
;
i
<
n
;
++
i
)
for
(
j
=
v1
[
i
];
j
<
v1
[
i
]
+
d1
[
i
];
++
j
)
{
k
=
e1
[
j
];
e2
[
v2
[
k
]
+
(
d2
[
k
]
++
)]
=
i
;
}
}
/*****************************************************************************
* *
* complement_sg(g1,g2) sets g2 to the complement of g1. *
* If g1 has loops then the loop set is also complemented; otherwise *
* no loops are created. g2 must exist and be initialised. *
* *
*****************************************************************************/
void
complement_sg
(
sparsegraph
*
g1
,
sparsegraph
*
g2
)
{
int
*
e1
,
*
d1
,
*
e2
,
*
d2
;
size_t
*
v1
,
*
v2
,
j
,
ndec
;
int
i
,
l
,
m
,
n
;
int
loops
;
CHECK_SWG
(
g1
,
"complement_sg"
);
n
=
g1
->
nv
;
SG_VDE
(
g1
,
v1
,
d1
,
e1
);
loops
=
0
;
for
(
i
=
0
;
i
<
n
;
++
i
)
for
(
j
=
v1
[
i
];
j
<
v1
[
i
]
+
d1
[
i
];
++
j
)
if
(
e1
[
j
]
==
i
)
++
loops
;
if
(
loops
>
1
)
ndec
=
n
*
(
size_t
)
n
-
g1
->
nde
;
else
ndec
=
n
*
(
size_t
)
n
-
n
-
g1
->
nde
;
SG_ALLOC
(
*
g2
,
n
,
ndec
,
"converse_sg"
);
g2
->
nv
=
n
;
SG_VDE
(
g2
,
v2
,
d2
,
e2
);
m
=
SETWORDSNEEDED
(
n
);
#if !MAXN
DYNALLOC1
(
set
,
workset
,
workset_sz
,
m
,
"putorbits"
);
#endif
DYNFREE
(
g2
->
w
,
g2
->
wlen
);
ndec
=
0
;
for
(
i
=
0
;
i
<
n
;
++
i
)
{
EMPTYSET
(
workset
,
m
);
for
(
j
=
v1
[
i
];
j
<
v1
[
i
]
+
d1
[
i
];
++
j
)
ADDELEMENT
(
workset
,
e1
[
j
]);
if
(
loops
==
0
)
ADDELEMENT
(
workset
,
i
);
v2
[
i
]
=
ndec
;
for
(
l
=
0
;
l
<
n
;
++
l
)
if
(
!
ISELEMENT
(
workset
,
l
))
e2
[
ndec
++
]
=
l
;
d2
[
i
]
=
ndec
-
v2
[
i
];
}
g2
->
nde
=
ndec
;
}
/*****************************************************************************
* *
* mathon_sg(g1,g2) performs a Mathon doubling operation on g1, *
* leaving the result in g2. g2 must exist and be initialised. *
* *
*****************************************************************************/
void
mathon_sg
(
sparsegraph
*
g1
,
sparsegraph
*
g2
)
{
int
*
e1
,
*
d1
,
*
e2
,
*
d2
;
size_t
*
v1
,
*
v2
,
j
;
int
i
,
k
,
m
,
n1
,
n2
;
CHECK_SWG
(
g1
,
"mathon_sg"
);
n1
=
g1
->
nv
;
n2
=
2
*
n1
+
2
;
SG_ALLOC
(
*
g2
,
n2
,
n2
*
(
size_t
)
n1
,
"mathon_sg"
);
g2
->
nv
=
n2
;
g2
->
nde
=
n2
*
(
size_t
)
n1
;
DYNFREE
(
g2
->
w
,
g2
->
wlen
);
SG_VDE
(
g1
,
v1
,
d1
,
e1
);
SG_VDE
(
g2
,
v2
,
d2
,
e2
);
m
=
SETWORDSNEEDED
(
n1
);
#if !MAXN
DYNALLOC1
(
set
,
workset
,
workset_sz
,
m
,
"mathon_sg"
);
#endif
for
(
i
=
0
;
i
<
n2
;
++
i
)
{
v2
[
i
]
=
i
*
(
size_t
)
n1
;
d2
[
i
]
=
0
;
}
for
(
i
=
0
;
i
<
n1
;
++
i
)
{
e2
[
v2
[
0
]
+
(
d2
[
0
]
++
)]
=
i
+
1
;
e2
[
v2
[
i
+
1
]
+
(
d2
[
i
+
1
]
++
)]
=
0
;
e2
[
v2
[
n1
+
1
]
+
(
d2
[
n1
+
1
]
++
)]
=
i
+
n1
+
2
;
e2
[
v2
[
i
+
n1
+
2
]
+
(
d2
[
i
+
n1
+
2
]
++
)]
=
n1
+
1
;
}
for
(
i
=
0
;
i
<
n1
;
++
i
)
{
EMPTYSET
(
workset
,
m
);
for
(
j
=
v1
[
i
];
j
<
v1
[
i
]
+
d1
[
i
];
++
j
)
{
k
=
e1
[
j
];
if
(
k
==
i
)
continue
;
/* ignore loops */
ADDELEMENT
(
workset
,
k
);
e2
[
v2
[
i
+
1
]
+
(
d2
[
i
+
1
]
++
)]
=
k
+
1
;
e2
[
v2
[
i
+
n1
+
2
]
+
(
d2
[
i
+
n1
+
2
]
++
)]
=
k
+
n1
+
2
;
}
for
(
k
=
0
;
k
<
n1
;
++
k
)
if
(
k
!=
i
&&
!
ISELEMENT
(
workset
,
k
))
{
e2
[
v2
[
i
+
1
]
+
(
d2
[
i
+
1
]
++
)]
=
k
+
n1
+
2
;
e2
[
v2
[
k
+
n1
+
2
]
+
(
d2
[
k
+
n1
+
2
]
++
)]
=
i
+
1
;
}
}
}
/*****************************************************************************
* *
* mathon(g1,m1,n1,g2,m2,n2) performs a Mathon doubling operation on g1, *
* leaving the result in g2. *
* m1,n1 and m2,n2 are the values of m,n before and after the operation. *
* *
*****************************************************************************/
void
mathon
(
graph
*
g1
,
int
m1
,
int
n1
,
graph
*
g2
,
int
m2
,
int
n2
)
{
int
i
,
j
,
ii
,
jj
;
long
li
;
set
*
rowptr
,
*
gp
;
for
(
li
=
(
long
)
m2
*
(
long
)
n2
;
--
li
>=
0
;)
g2
[
li
]
=
0
;
for
(
i
=
1
;
i
<=
n1
;
++
i
)
{
ii
=
i
+
n1
+
1
;
gp
=
GRAPHROW
(
g2
,
0
,
m2
);
/* unnecessarily convoluted code */
ADDELEMENT
(
gp
,
i
);
/* needed to avoid compiler bug */
gp
=
GRAPHROW
(
g2
,
i
,
m2
);
/* in MSDOS version */
ADDELEMENT
(
gp
,
0
);
gp
=
GRAPHROW
(
g2
,
n1
+
1
,
m2
);
ADDELEMENT
(
gp
,
ii
);
gp
=
GRAPHROW
(
g2
,
ii
,
m2
);
ADDELEMENT
(
gp
,
n1
+
1
);
}
for
(
i
=
0
,
rowptr
=
g1
;
i
<
n1
;
++
i
,
rowptr
+=
m1
)
for
(
j
=
0
;
j
<
n1
;
++
j
)
if
(
j
!=
i
)
{
ii
=
i
+
n1
+
2
;
jj
=
j
+
n1
+
2
;
if
(
ISELEMENT
(
rowptr
,
j
))
{
gp
=
GRAPHROW
(
g2
,
i
+
1
,
m2
);
ADDELEMENT
(
gp
,
j
+
1
);
gp
=
GRAPHROW
(
g2
,
ii
,
m2
);
ADDELEMENT
(
gp
,
jj
);
}
else
{
gp
=
GRAPHROW
(
g2
,
i
+
1
,
m2
);
ADDELEMENT
(
gp
,
jj
);
gp
=
GRAPHROW
(
g2
,
ii
,
m2
);
ADDELEMENT
(
gp
,
j
+
1
);
}
}
}
/*****************************************************************************
* *
* rangraph(g,digraph,invprob,m,n) makes a random graph (or digraph if *
* digraph!=FALSE) with edge probability 1/invprob. *
* *
*****************************************************************************/
void
rangraph
(
graph
*
g
,
boolean
digraph
,
int
invprob
,
int
m
,
int
n
)
{
int
i
,
j
;
long
li
;
set
*
row
,
*
col
;
for
(
li
=
(
long
)
m
*
(
long
)
n
;
--
li
>=
0
;)
g
[
li
]
=
0
;
for
(
i
=
0
,
row
=
g
;
i
<
n
;
++
i
,
row
+=
m
)
if
(
digraph
)
{
for
(
j
=
0
;
j
<
n
;
++
j
)
if
(
KRAN
(
invprob
)
==
0
)
ADDELEMENT
(
row
,
j
);
}
else
{
for
(
j
=
i
+
1
,
col
=
GRAPHROW
(
g
,
j
,
m
);
j
<
n
;
++
j
,
col
+=
m
)
if
(
KRAN
(
invprob
)
==
0
)
{
ADDELEMENT
(
row
,
j
);
ADDELEMENT
(
col
,
i
);
}
}
}
/*****************************************************************************
* *
* rangraph2(g,digraph,p1,p2,m,n) makes a random graph (or digraph if *
* digraph!=FALSE) with edge probability p1/p2. *
* *
*****************************************************************************/
void
rangraph2
(
graph
*
g
,
boolean
digraph
,
int
p1
,
int
p2
,
int
m
,
int
n
)
{
int
i
,
j
;
long
li
;
set
*
row
,
*
col
;
for
(
li
=
(
long
)
m
*
(
long
)
n
;
--
li
>=
0
;)
g
[
li
]
=
0
;
for
(
i
=
0
,
row
=
g
;
i
<
n
;
++
i
,
row
+=
m
)
if
(
digraph
)
{
for
(
j
=
0
;
j
<
n
;
++
j
)
if
(
KRAN
(
p2
)
<
p1
)
ADDELEMENT
(
row
,
j
);
}
else
for
(
j
=
i
+
1
,
col
=
GRAPHROW
(
g
,
j
,
m
);
j
<
n
;
++
j
,
col
+=
m
)
if
(
KRAN
(
p2
)
<
p1
)
{
ADDELEMENT
(
row
,
j
);
ADDELEMENT
(
col
,
i
);
}
}
/*****************************************************************************
* *
* rangraph2_sg(sg,digraph,p1,p2,n) makes a random graph (or digraph if *
* digraph!=FALSE) with edge probability p1/p2. sg must be initialised. *
* *
*****************************************************************************/
void
rangraph2_sg
(
sparsegraph
*
sg
,
boolean
digraph
,
int
p1
,
int
p2
,
int
n
)
{
int
i
,
j
,
k
;
int
*
dd
,
*
ee
;
double
rn
,
expec
,
var
,
sd
;
int
ldeg
;
size_t
*
vv
,
inc
,
nde
;
sg
->
nv
=
n
;
rn
=
n
;
expec
=
(
rn
*
rn
-
rn
)
*
(
double
)
p1
/
(
double
)
p2
;
var
=
expec
*
(
double
)(
p2
-
p1
)
/
(
double
)
p2
;
if
(
!
digraph
)
var
*=
2.0
;
sd
=
1.0
;
if
(
var
>
1.0
)
for
(
i
=
0
;
i
<
19
;
++
i
)
sd
=
(
sd
+
var
/
sd
)
/
2.0
;
inc
=
sd
+
20
;
SG_ALLOC
(
*
sg
,
n
,(
size_t
)
expec
+
4
*
inc
,
"rangraph2_sg"
);
SG_VDE
(
sg
,
vv
,
dd
,
ee
);
DYNFREE
(
sg
->
w
,
sg
->
wlen
);
for
(
i
=
0
;
i
<
n
;
++
i
)
dd
[
i
]
=
0
;
vv
[
0
]
=
0
;
nde
=
0
;
if
(
!
digraph
)
{
for
(
i
=
0
;
i
<
n
;
++
i
)
{
ldeg
=
0
;
for
(
j
=
i
+
1
;
j
<
n
;
++
j
)
if
(
KRAN
(
p2
)
<
p1
)
{
nde
+=
2
;
if
(
nde
>
sg
->
elen
)
{
DYNREALLOC
(
int
,
sg
->
e
,
sg
->
elen
,
sg
->
elen
+
inc
,
"rangraph2_sg realloc"
);
ee
=
sg
->
e
;
}
ee
[
vv
[
i
]
+
ldeg
++
]
=
j
;
++
dd
[
j
];
}
if
(
i
<
n
-1
)
vv
[
i
+
1
]
=
vv
[
i
]
+
dd
[
i
]
+
ldeg
;
dd
[
i
]
=
ldeg
;
}
for
(
i
=
0
;
i
<
n
;
++
i
)
for
(
k
=
0
;
k
<
dd
[
i
];
++
k
)
{
j
=
ee
[
vv
[
i
]
+
k
];
if
(
j
>
i
)
ee
[
vv
[
j
]
+
dd
[
j
]
++
]
=
i
;
}
sg
->
nde
=
nde
;
}
else
{
for
(
i
=
0
;
i
<
n
;
++
i
)
{
ldeg
=
0
;
for
(
j
=
0
;
j
<
n
;
++
j
)
if
(
j
!=
i
&&
KRAN
(
p2
)
<
p1
)
{
++
nde
;
if
(
nde
>
sg
->
elen
)
{
DYNREALLOC
(
int
,
sg
->
e
,
sg
->
elen
,
sg
->
elen
+
inc
,
"rangraph2_sg realloc"
);
ee
=
sg
->
e
;
}
ee
[
vv
[
i
]
+
ldeg
++
]
=
j
;
}
if
(
i
<
n
-1
)
vv
[
i
+
1
]
=
vv
[
i
]
+
ldeg
;
dd
[
i
]
=
ldeg
;
}
sg
->
nde
=
nde
;
}
}
/****************************************************************************/
static
void
putsequence
(
FILE
*
f
,
int
*
x
,
int
linelength
,
int
n
)
/* Write n integers to f with equal values collapsed.
* labelorg is used. */
{
char
s
[
60
];
int
j
,
v1
,
v2
,
xval
,
curlen
;
curlen
=
0
;
v1
=
0
;
while
(
v1
<
n
)
{
xval
=
x
[
v1
];
for
(
v2
=
v1
;
v2
<
n
-
1
&&
x
[
v2
+
1
]
==
xval
;
++
v2
)
{}
j
=
itos
(
v1
+
labelorg
,
s
);
if
(
v2
>
v1
)
{
s
[
j
++
]
=
'-'
;
j
+=
itos
(
v2
+
labelorg
,
&
s
[
j
]);
}
s
[
j
++
]
=
':'
;
j
+=
itos
(
xval
,
&
s
[
j
]);
s
[
j
]
=
' '
;
s
[
j
+
1
]
=
'\0'
;
if
(
linelength
>
0
&&
curlen
+
j
>=
linelength
)
{
PUTC
(
'\n'
,
f
);
curlen
=
0
;
}
curlen
+=
j
+
1
;
putstring
(
f
,
s
);
v1
=
v2
+
1
;
}
PUTC
(
'\n'
,
f
);
}
/****************************************************************************/
static
void
putnumbers
(
FILE
*
f
,
int
*
x
,
int
linelength
,
int
n
)
/* Write n integers to f with equal values combined as multiplicities.
* labelorg is NOT used. */
{
char
s
[
60
];
int
j
,
v1
,
v2
,
xval
,
curlen
;
curlen
=
0
;
v1
=
0
;
while
(
v1
<
n
)
{
xval
=
x
[
v1
];
for
(
v2
=
v1
;
v2
<
n
-
1
&&
x
[
v2
+
1
]
==
xval
;
++
v2
)
{}
if
(
v2
>
v1
)
{
j
=
itos
(
v2
-
v1
+
1
,
s
);
s
[
j
++
]
=
'*'
;
}
else
j
=
0
;
j
+=
itos
(
xval
,
&
s
[
j
]);
s
[
j
]
=
' '
;
s
[
j
+
1
]
=
'\0'
;
if
(
linelength
>
0
&&
curlen
+
j
>=
linelength
)
{
PUTC
(
'\n'
,
f
);
curlen
=
0
;
}
curlen
+=
j
+
1
;
putstring
(
f
,
s
);
v1
=
v2
+
1
;
}
PUTC
(
'\n'
,
f
);
}
/*****************************************************************************
* *
* putdegs(f,g,linelength,m,n) writes the degree of each vertex of g to *
* file f, using at most linelength characters per line (excluding '\n'). *
* A value of linelength <= 0 dictates no line breaks at all. *
* labelorg is used. *
* *
* FUNCTIONS CALLED : itos(),putstring(),setsize() *
* *
*****************************************************************************/
void
putdegs
(
FILE
*
f
,
graph
*
g
,
int
linelength
,
int
m
,
int
n
)
{
int
i
;
graph
*
gp
;
#if !MAXN
DYNALLOC1
(
int
,
workperm
,
workperm_sz
,
n
+
2
,
"putdegs"
);
#endif
for
(
i
=
0
,
gp
=
g
;
i
<
n
;
++
i
,
gp
+=
M
)
workperm
[
i
]
=
setsize
(
gp
,
m
);
putsequence
(
f
,
workperm
,
linelength
,
n
);
}
/*****************************************************************************
* *
* putdegseq(f,g,linelength,m,n) writes the sorted degree sequence of g *
* file f, using at most linelength characters per line (excluding '\n'). *
* A value of linelength <= 0 dictates no line breaks at all. *
* *
*****************************************************************************/
void
putdegseq
(
FILE
*
f
,
graph
*
g
,
int
linelength
,
int
m
,
int
n
)
{
int
i
;
graph
*
gp
;
#if !MAXN
DYNALLOC1
(
int
,
workperm
,
workperm_sz
,
n
,
"putdegs"
);
#endif
for
(
i
=
0
,
gp
=
g
;
i
<
n
;
++
i
,
gp
+=
M
)
workperm
[
i
]
=
setsize
(
gp
,
m
);
sort1int
(
workperm
,
n
);
putnumbers
(
f
,
workperm
,
linelength
,
n
);
}
/*****************************************************************************
* *
* putdegs_sg(f,sg,linelength) writes the degree of each vertex of sg to *
* file f, using at most linelength characters per line (excluding '\n'). *
* A value of linelength <= 0 dictates no line breaks at all. *
* labelorg is used. *
* *
* FUNCTIONS CALLED : itos(),putstring(), *
* *
*****************************************************************************/
void
putdegs_sg
(
FILE
*
f
,
sparsegraph
*
sg
,
int
linelength
)
{
putsequence
(
f
,
sg
->
d
,
linelength
,
sg
->
nv
);
}
/*****************************************************************************
* *
* putdegseq_sg(f,sg,linelength) writes the sorted degree sequence of sg to *
* file f, using at most linelength characters per line (excluding '\n'). *
* A value of linelength <= 0 dictates no line breaks at all. *
* *
*****************************************************************************/
void
putdegseq_sg
(
FILE
*
f
,
sparsegraph
*
sg
,
int
linelength
)
{
int
i
;
#if !MAXN
DYNALLOC1
(
int
,
workperm
,
workperm_sz
,
sg
->
nv
,
"putdegs"
);
#endif
for
(
i
=
0
;
i
<
sg
->
nv
;
++
i
)
workperm
[
i
]
=
sg
->
d
[
i
];
sort1int
(
workperm
,
sg
->
nv
);
putnumbers
(
f
,
workperm
,
linelength
,
sg
->
nv
);
}
/*****************************************************************************
* *
* complement(g,m,n) replaces the graph g by its complement *
* No loops are created unless there are loops present, in which case the *
* loops are also complemented. *
* *
*****************************************************************************/
void
complement
(
graph
*
g
,
int
m
,
int
n
)
{
boolean
loops
;
int
i
,
j
;
graph
*
gp
;
#if !MAXN
DYNALLOC1
(
set
,
workset
,
workset_sz
,
m
,
"complement"
);
#endif
loops
=
FALSE
;
for
(
i
=
0
,
gp
=
g
;
i
<
n
&&
!
loops
;
++
i
,
gp
+=
M
)
if
(
ISELEMENT
(
gp
,
i
))
loops
=
TRUE
;
EMPTYSET
(
workset
,
m
);
for
(
i
=
0
;
i
<
n
;
++
i
)
ADDELEMENT
(
workset
,
i
);
for
(
i
=
0
,
gp
=
g
;
i
<
n
;
++
i
,
gp
+=
M
)
{
for
(
j
=
0
;
j
<
M
;
++
j
)
gp
[
j
]
=
workset
[
j
]
&
~
gp
[
j
];
if
(
!
loops
)
DELELEMENT
(
gp
,
i
);
}
}
/*****************************************************************************
* *
* converse(g,m,n) replaces the digraph g by its converse. *
* There is no effect on an undirected graph. *
* *
*****************************************************************************/
void
converse
(
graph
*
g
,
int
m
,
int
n
)
{
int
i
,
j
;
graph
*
gi
,
*
gj
;
for
(
i
=
0
,
gi
=
g
;
i
<
n
;
++
i
,
gi
+=
M
)
for
(
j
=
i
+
1
,
gj
=
gi
+
M
;
j
<
n
;
++
j
,
gj
+=
M
)
if
((
ISELEMENT
(
gi
,
j
)
!=
0
)
+
(
ISELEMENT
(
gj
,
i
)
!=
0
)
==
1
)
{
FLIPELEMENT
(
gi
,
j
);
FLIPELEMENT
(
gj
,
i
);
}
}
/*****************************************************************************
* *
* naututil_check() checks that this file is compiled compatibly with the *
* given parameters. If not, call exit(1). *
* *
*****************************************************************************/
void
naututil_check
(
int
wordsize
,
int
m
,
int
n
,
int
version
)
{
if
(
wordsize
!=
WORDSIZE
)
{
fprintf
(
ERRFILE
,
"Error: WORDSIZE mismatch in naututil.c
\n
"
);
exit
(
1
);
}
#if MAXN
if
(
m
>
MAXM
)
{
fprintf
(
ERRFILE
,
"Error: MAXM inadequate in naututil.c
\n
"
);
exit
(
1
);
}
if
(
n
>
MAXN
)
{
fprintf
(
ERRFILE
,
"Error: MAXN inadequate in naututil.c
\n
"
);
exit
(
1
);
}
#endif
if
(
version
<
NAUTYREQUIRED
)
{
fprintf
(
ERRFILE
,
"Error: naututil.c version mismatch
\n
"
);
exit
(
1
);
}
}
/*****************************************************************************
* *
* naututil_freedyn() - free the dynamic memory in this module *
* *
*****************************************************************************/
void
naututil_freedyn
(
void
)
{
echunk
*
ec1
,
*
ec2
;
#if !MAXN
DYNFREE
(
workperm
,
workperm_sz
);
DYNFREE
(
workset
,
workset_sz
);
#endif
ec1
=
first_echunk
.
next
;
while
(
ec1
)
{
ec2
=
ec1
->
next
;
FREES
(
ec1
);
ec1
=
ec2
;
}
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Tue, Oct 27, 7:20 PM (1 d, 5 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
406161
Default Alt Text
naututil.c (102 KB)
Attached To
Mode
R272 SoC_NEM_Synthesis
Attached
Detach File
Event Timeline