Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F27033118
nautinv.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Authored By
Unknown
Size
64 KB
Referenced Files
None
Subscribers
None
nautinv.c
View Options
/*****************************************************************************
* *
* Vertex-invariants source file for nauty 2.6. *
* *
* Copyright (1989-2013) Brendan McKay. All rights reserved. *
* Subject to waivers and disclaimers in nauty.h. *
* *
* CHANGE HISTORY *
* 13-Mar-90 : initial release for version 1.5 *
* 10-Nov-90 : changes for version 1.6 : *
* - added dummy routine nautinv_null() *
* 27-Aug-92 : renamed to version 1.7, no changes to this file *
* 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 : changes for version 1.9 : *
* - added invariant routine adjacencies() *
* 20-Jun-96 : changes for version 2.0 : *
* - added invariants cellfano() and cellfano2() *
* 11-Jul-96 - added dynamic allocation *
* 21-Oct-98 - use shortish in place of short for BIGNAUTY *
* 9-Jan-00 - added nautinv_check() *
* 12-Feb-00 - minor code formatting *
* 16-Nov-00 - made changes listed in nauty.h *
* 22-Apr-01 : changes for version 2.1 : *
* - made all large dynamic memory external to routines *
* - added nautinv_freedyn() to free all such memory *
* - include nautinv.h rather than naututil.h *
* - removed nautinv_null() *
* - added code to facilitate compilation into Magma *
* - removed EXTDEFS *
* 12-Jul-01 - use invararg in distances() *
* - fixed comments in ind and cliq routines *
* 21-Nov-01 : use NAUTYREQUIRED in nautinv_check() *
* 10-Dec-06 : remove BIGNAUTY *
* 10-Nov-09 : remove types shortish and permutation *
* 23-Nov-09 : add refinvar() *
* 12-Jun-10 : fixed identical errors in cellcliq() and cellind() *
* 15-Jan-12 : add TLS_ATTR attributes *
* 23-Aug-12 : fix getbigcells(), thanks to Fatih Demirkale *
* 23-Jan-13 : add some parens to satisfy icc *
* *
*****************************************************************************/
#define ONE_WORD_SETS
#include
"nautinv.h"
#if MAXM==1
#define M 1
#else
#define M m
#endif
#define MASH(l,i) ((((l) ^ 056345) + (i)) & 077777)
/* : expression whose long value depends only on long l and int/long i.
Anything goes, preferably non-commutative. */
#define CLEANUP(l) ((int)((l) % 077777))
/* : expression whose value depends on long l and is less than 077777
when converted to int then short. Anything goes. */
#define ACCUM(x,y) x = (((x) + (y)) & 077777)
/* : must be commutative. */
static
const
int
fuzz1
[]
=
{
037541
,
061532
,
005257
,
026416
};
static
const
int
fuzz2
[]
=
{
006532
,
070236
,
035523
,
062437
};
#define FUZZ1(x) ((x) ^ fuzz1[(x)&3])
#define FUZZ2(x) ((x) ^ fuzz2[(x)&3])
#define MAXCLIQUE 10
/* max clique size for cliques() and maxindset() */
#if MAXN
static
TLS_ATTR
int
workshort
[
MAXN
+
2
];
static
TLS_ATTR
int
vv
[
MAXN
],
ww
[
MAXN
];
static
TLS_ATTR
int
workperm
[
MAXN
];
static
TLS_ATTR
int
bucket
[
MAXN
+
2
];
static
TLS_ATTR
int
count
[
MAXN
];
static
TLS_ATTR
set
workset
[
MAXM
];
static
TLS_ATTR
set
w01
[
MAXM
],
w02
[
MAXM
],
w03
[
MAXM
],
w12
[
MAXM
],
w13
[
MAXM
],
w23
[
MAXM
];
static
TLS_ATTR
set
pt0
[
MAXM
],
pt1
[
MAXM
],
pt2
[
MAXM
];
static
TLS_ATTR
set
wss
[
MAXCLIQUE
-1
][
MAXM
];
static
TLS_ATTR
set
ws1
[
MAXM
],
ws2
[
MAXM
];
#else
DYNALLSTAT
(
int
,
workshort
,
workshort_sz
);
DYNALLSTAT
(
int
,
vv
,
vv_sz
);
DYNALLSTAT
(
int
,
ww
,
ww_sz
);
DYNALLSTAT
(
int
,
workperm
,
workperm_sz
);
DYNALLSTAT
(
int
,
bucket
,
bucket_sz
);
DYNALLSTAT
(
int
,
count
,
count_sz
);
DYNALLSTAT
(
set
,
ws1
,
ws1_sz
);
DYNALLSTAT
(
set
,
ws2
,
ws2_sz
);
DYNALLSTAT
(
set
,
workset
,
workset_sz
);
DYNALLSTAT
(
set
,
w01
,
w01_sz
);
DYNALLSTAT
(
set
,
w02
,
w02_sz
);
DYNALLSTAT
(
set
,
w03
,
w03_sz
);
DYNALLSTAT
(
set
,
w12
,
w12_sz
);
DYNALLSTAT
(
set
,
w13
,
w13_sz
);
DYNALLSTAT
(
set
,
w23
,
w23_sz
);
DYNALLSTAT
(
set
,
pt0
,
pt0_sz
);
DYNALLSTAT
(
set
,
pt1
,
pt1_sz
);
DYNALLSTAT
(
set
,
pt2
,
pt2_sz
);
DYNALLSTAT
(
set
,
wss
,
wss_sz
);
#endif
/* aproto: header new_nauty_protos.h */
/*****************************************************************************
* *
* This file contains a number of procedures which compute vertex-invariants *
* for stronger partition refinement. Since entirely different *
* vertex-invariants seem to work better for different types of graph, we *
* cannot do more than give a small collection of representative examples. *
* Any serious computations with difficult graphs may well need to use *
* specially-written vertex-invariants. The use of vertex-invariants *
* procedures is supported by nauty from version 1.5 onwards, via the *
* options userinvarproc, mininvarlevel, maxinvarlevel and invararg. *
* The meaning of these fields in detail are as follows: *
* userinvarproc is the address of the vertex-invariant procedure. If *
* no vertex-invariants is required, this field should *
* have the value NULL. *
* maxinvarlevel The absolute value of this is the maximum level in the *
* search tree at which the vertex-invariant will be *
* computed. The root of the tree is at level 1, so the *
* vertex-invariant will not be invoked at all if *
* maxinvarlevel==0. Negative values of maxinvarlevel *
* request nauty to not compute the vertex-invariant at *
* a level greater than that of the earliest node (if any) *
* on the path to the first leaf of the search tree at *
* which the vertex-invariant refines the partition. *
* mininvarlevel The absolute value of this is the minimum level in the *
* search tree at which the vertex-invariant will be *
* computed. The root of the tree is at level 1, so there *
* is no effective limit if mininvarlevel is -1, 0 or 1. *
* Negative values of mininvarlevel request nauty to not *
* compute the vertex-invariant at a level less than *
* that of the earliest node (if any) on the path to the *
* first leaf of the search tree at which the *
* vertex-invariant refines the partition. *
* invararg is passed to the vertex-invariant procedure via the *
* argument of the same name. It can be used by the *
* procedure for any purpose. *
* Note that negative values of maxinvarlevel and mininvarlevel make the *
* canonical labelling invalid, but can speed automorphism group finding. *
* Nauty already knows this and takes their absolute values. *
* *
* A vertex-invariant must be declared thus: *
* void invarproc(g,lab,ptn,level,numcells,tvpos,invar,invararg,digraph,m,n) *
* All of these arguments must be treated as read-only except for invar. *
* g : the graph, exactly as passed to nauty() *
* lab,ptn : the current partition nest (see nauty.h for the format) *
* level : the level of this node in the search tree. *
* numcells : the number of cells in the partition at this node. *
* tvpos : the index in (lab,ptn) of one cell in the partition. *
* If level <= 1, the cell will be the first fragment of the *
* first active cell (as provided by the initial call to nauty), *
* or the first cell, if there were no active cells. *
* If level > 1, the cell will be the singleton cell which was *
* created to make this node of the search tree from its parent. *
* invararg : a copy of options.invararg *
* digraph : a copy of options.digraph *
* m,n : size parameters as passed to nauty() *
* invar : an array to return the answer in. The procedure must put in *
* each invar[i] (0 <= i < n) an invariant of the 6-tuple *
* (<vertex i>,g,<the partition nest to this level>,level, *
* invararg,digraph) *
* Note that invar[] is declared as an int array. Since the *
* absolute value of the invariant is irrelevant, only the *
* comparative values, any short, int or long value can be *
* assigned to the entries of invar[] without fear. However, *
* you should assign a value less than 077777 to ensure machine- *
* independence of the canonical labelling. *
* *
* The refinement procedure has already been called before the invariant *
* procedure is called. That means that the partition is equitable if *
* digraph==FALSE. *
* *
*****************************************************************************/
/*****************************************************************************
* *
* twopaths() assigns to each vertex v the sum of the weights of each vertex *
* which can be reached from v along a walk of length two (including itself *
* usually). The weight of each vertex w is defined as the ordinal number *
* of the cell containing w, starting at 1 for the first cell. *
* *
*****************************************************************************/
void
twopaths
(
graph
*
g
,
int
*
lab
,
int
*
ptn
,
int
level
,
int
numcells
,
int
tvpos
,
int
*
invar
,
int
invararg
,
boolean
digraph
,
int
m
,
int
n
)
{
int
i
,
v
,
w
;
int
wt
;
set
*
gv
,
*
gw
;
#if !MAXN
DYNALLOC1
(
set
,
workset
,
workset_sz
,
m
,
"twopaths"
);
DYNALLOC1
(
int
,
workshort
,
workshort_sz
,
n
+
2
,
"twopaths"
);
#endif
wt
=
1
;
for
(
i
=
0
;
i
<
n
;
++
i
)
{
workshort
[
lab
[
i
]]
=
wt
;
if
(
ptn
[
i
]
<=
level
)
++
wt
;
}
for
(
v
=
0
,
gv
=
(
set
*
)
g
;
v
<
n
;
++
v
,
gv
+=
M
)
{
EMPTYSET
(
workset
,
m
);
w
=
-1
;
while
((
w
=
nextelement
(
gv
,
M
,
w
))
>=
0
)
{
gw
=
GRAPHROW
(
g
,
w
,
m
);
for
(
i
=
M
;
--
i
>=
0
;)
UNION
(
workset
[
i
],
gw
[
i
]);
}
wt
=
0
;
w
=
-1
;
while
((
w
=
nextelement
(
workset
,
M
,
w
))
>=
0
)
ACCUM
(
wt
,
workshort
[
w
]);
invar
[
v
]
=
wt
;
}
}
/*****************************************************************************
* *
* quadruples() assigns to each vertex v a value depending on the set of *
* weights w(v,v1,v2,v3), where w(v,v1,v2,v3) depends on the number of *
* vertices adjacent to an odd number of {v,v1,v2,v3}, and to the cells *
* that v,v1,v2,v3 belong to. {v,v1,v2,v3} are permitted to range over all *
* distinct 4-tuples which contain at least one member in the cell tvpos. *
* *
*****************************************************************************/
void
quadruples
(
graph
*
g
,
int
*
lab
,
int
*
ptn
,
int
level
,
int
numcells
,
int
tvpos
,
int
*
invar
,
int
invararg
,
boolean
digraph
,
int
m
,
int
n
)
{
int
i
,
pc
;
setword
sw
;
set
*
gw
;
int
wt
;
int
v
,
iv
,
v1
,
v2
,
v3
;
set
*
gv
;
long
wv
,
wv1
,
wv2
,
wv3
;
#if !MAXN
DYNALLOC1
(
int
,
workshort
,
workshort_sz
,
n
+
2
,
"quadruples"
);
DYNALLOC1
(
set
,
ws1
,
ws1_sz
,
m
,
"quadruples"
);
DYNALLOC1
(
set
,
workset
,
workset_sz
,
m
,
"quadruples"
);
#endif
for
(
i
=
n
;
--
i
>=
0
;)
invar
[
i
]
=
0
;
wt
=
1
;
for
(
i
=
0
;
i
<
n
;
++
i
)
{
workshort
[
lab
[
i
]]
=
FUZZ2
(
wt
);
if
(
ptn
[
i
]
<=
level
)
++
wt
;
}
iv
=
tvpos
-
1
;
do
{
v
=
lab
[
++
iv
];
gv
=
GRAPHROW
(
g
,
v
,
m
);
wv
=
workshort
[
v
];
for
(
v1
=
0
;
v1
<
n
-2
;
++
v1
)
{
wv1
=
workshort
[
v1
];
if
(
wv1
==
wv
&&
v1
<=
v
)
continue
;
wv1
+=
wv
;
gw
=
GRAPHROW
(
g
,
v1
,
m
);
for
(
i
=
M
;
--
i
>=
0
;)
workset
[
i
]
=
gv
[
i
]
^
gw
[
i
];
for
(
v2
=
v1
+
1
;
v2
<
n
-1
;
++
v2
)
{
wv2
=
workshort
[
v2
];
if
(
wv2
==
wv
&&
v2
<=
v
)
continue
;
wv2
+=
wv1
;
gw
=
GRAPHROW
(
g
,
v2
,
m
);
for
(
i
=
M
;
--
i
>=
0
;)
ws1
[
i
]
=
workset
[
i
]
^
gw
[
i
];
for
(
v3
=
v2
+
1
;
v3
<
n
;
++
v3
)
{
wv3
=
workshort
[
v3
];
if
(
wv3
==
wv
&&
v3
<=
v
)
continue
;
wv3
+=
wv2
;
gw
=
GRAPHROW
(
g
,
v3
,
m
);
pc
=
0
;
for
(
i
=
M
;
--
i
>=
0
;)
if
((
sw
=
ws1
[
i
]
^
gw
[
i
])
!=
0
)
pc
+=
POPCOUNT
(
sw
);
wt
=
(
FUZZ1
(
pc
)
+
wv3
)
&
077777
;
wt
=
FUZZ2
(
wt
);
ACCUM
(
invar
[
v
],
wt
);
ACCUM
(
invar
[
v1
],
wt
);
ACCUM
(
invar
[
v2
],
wt
);
ACCUM
(
invar
[
v3
],
wt
);
}
}
}
}
while
(
ptn
[
iv
]
>
level
);
}
/*****************************************************************************
* *
* triples() assigns to each vertex v a value depending on the set of *
* weights w(v,v1,v2), where w(v,v1,v2) depends on the number of vertices *
* adjacent to an odd number of {v,v1,v2}, and to the cells that *
* v,v1,v2 belong to. {v,v1,v2} are permitted to range over all distinct *
* triples which contain at least one member in the cell tvpos. *
* *
*****************************************************************************/
void
triples
(
graph
*
g
,
int
*
lab
,
int
*
ptn
,
int
level
,
int
numcells
,
int
tvpos
,
int
*
invar
,
int
invararg
,
boolean
digraph
,
int
m
,
int
n
)
{
int
i
,
pc
;
setword
sw
;
set
*
gw
;
int
wt
;
int
v
,
iv
,
v1
,
v2
;
set
*
gv
;
long
wv
,
wv1
,
wv2
;
#if !MAXN
DYNALLOC1
(
set
,
workset
,
workset_sz
,
m
,
"triples"
);
DYNALLOC1
(
int
,
workshort
,
workshort_sz
,
n
+
2
,
"triples"
);
#endif
for
(
i
=
n
;
--
i
>=
0
;)
invar
[
i
]
=
0
;
wt
=
1
;
for
(
i
=
0
;
i
<
n
;
++
i
)
{
workshort
[
lab
[
i
]]
=
FUZZ1
(
wt
);
if
(
ptn
[
i
]
<=
level
)
++
wt
;
}
iv
=
tvpos
-
1
;
do
{
v
=
lab
[
++
iv
];
gv
=
GRAPHROW
(
g
,
v
,
m
);
wv
=
workshort
[
v
];
for
(
v1
=
0
;
v1
<
n
-1
;
++
v1
)
{
wv1
=
workshort
[
v1
];
if
(
wv1
==
wv
&&
v1
<=
v
)
continue
;
wv1
+=
wv
;
gw
=
GRAPHROW
(
g
,
v1
,
m
);
for
(
i
=
M
;
--
i
>=
0
;)
workset
[
i
]
=
gv
[
i
]
^
gw
[
i
];
for
(
v2
=
v1
+
1
;
v2
<
n
;
++
v2
)
{
wv2
=
workshort
[
v2
];
if
(
wv2
==
wv
&&
v2
<=
v
)
continue
;
wv2
+=
wv1
;
gw
=
GRAPHROW
(
g
,
v2
,
m
);
pc
=
0
;
for
(
i
=
M
;
--
i
>=
0
;)
if
((
sw
=
workset
[
i
]
^
gw
[
i
])
!=
0
)
pc
+=
POPCOUNT
(
sw
);
wt
=
(
FUZZ1
(
pc
)
+
wv2
)
&
077777
;
wt
=
FUZZ2
(
wt
);
ACCUM
(
invar
[
v
],
wt
);
ACCUM
(
invar
[
v1
],
wt
);
ACCUM
(
invar
[
v2
],
wt
);
}
}
}
while
(
ptn
[
iv
]
>
level
);
}
/*****************************************************************************
* *
* adjtriang() assigns to each vertex v a value depending on the numbers *
* of common neighbours between each pair {v1,v2} of neighbours of v, and *
* which cells v1 and v2 lie in. The vertices v1 and v2 must be adjacent *
* if invararg == 0 and not adjacent if invararg == 1. *
* *
*****************************************************************************/
void
adjtriang
(
graph
*
g
,
int
*
lab
,
int
*
ptn
,
int
level
,
int
numcells
,
int
tvpos
,
int
*
invar
,
int
invararg
,
boolean
digraph
,
int
m
,
int
n
)
{
int
j
,
pc
;
setword
sw
;
set
*
gi
;
int
wt
;
int
i
,
v1
,
v2
;
boolean
v1v2
;
set
*
gv1
,
*
gv2
;
#if !MAXN
DYNALLOC1
(
set
,
workset
,
workset_sz
,
m
,
"adjtriang"
);
DYNALLOC1
(
int
,
workshort
,
workshort_sz
,
n
+
2
,
"adjtriang"
);
#endif
for
(
i
=
n
;
--
i
>=
0
;)
invar
[
i
]
=
0
;
wt
=
1
;
for
(
i
=
0
;
i
<
n
;
++
i
)
{
workshort
[
lab
[
i
]]
=
FUZZ1
(
wt
);
if
(
ptn
[
i
]
<=
level
)
++
wt
;
}
for
(
v1
=
0
,
gv1
=
g
;
v1
<
n
;
++
v1
,
gv1
+=
M
)
{
for
(
v2
=
(
digraph
?
0
:
v1
+
1
);
v2
<
n
;
++
v2
)
{
if
(
v2
==
v1
)
continue
;
v1v2
=
(
ISELEMENT
(
gv1
,
v2
)
!=
0
);
if
((
invararg
==
0
&&
!
v1v2
)
||
(
invararg
==
1
&&
v1v2
))
continue
;
wt
=
workshort
[
v1
];
ACCUM
(
wt
,
workshort
[
v2
]);
ACCUM
(
wt
,
v1v2
);
gv2
=
GRAPHROW
(
g
,
v2
,
m
);
for
(
i
=
M
;
--
i
>=
0
;)
workset
[
i
]
=
gv1
[
i
]
&
gv2
[
i
];
i
=
-1
;
while
((
i
=
nextelement
(
workset
,
M
,
i
))
>=
0
)
{
pc
=
0
;
gi
=
GRAPHROW
(
g
,
i
,
m
);
for
(
j
=
M
;
--
j
>=
0
;)
if
((
sw
=
workset
[
j
]
&
gi
[
j
])
!=
0
)
pc
+=
POPCOUNT
(
sw
);
pc
=
(
pc
+
wt
)
&
077777
;
ACCUM
(
invar
[
i
],
pc
);
}
}
}
}
/*****************************************************************************
* *
* getbigcells(ptn,level,minsize,bigcells,cellstart,cellsize,n) is an *
* auxiliary procedure to make a list of all the large cells in the current *
* partition. On entry, ptn, level and n have their usual meanings, *
* while minsize is the smallest size of an interesting cell. On return, *
* bigcells is the number of cells of size at least minsize, cellstart[0...] *
* contains their starting positions in ptn, and cellsize[0...] contain *
* their sizes. These two arrays are in increasing order of cell size, *
* then position. *
* *
*****************************************************************************/
void
getbigcells
(
int
*
ptn
,
int
level
,
int
minsize
,
int
*
bigcells
,
int
*
cellstart
,
int
*
cellsize
,
int
n
)
{
int
cell1
,
cell2
,
j
;
int
si
,
st
;
int
bc
,
i
,
h
;
bc
=
0
;
for
(
cell1
=
0
;
cell1
<
n
;
cell1
=
cell2
+
1
)
{
for
(
cell2
=
cell1
;
ptn
[
cell2
]
>
level
;
++
cell2
)
{}
if
(
cell2
>=
cell1
+
minsize
-
1
)
{
cellstart
[
bc
]
=
cell1
;
cellsize
[
bc
]
=
cell2
-
cell1
+
1
;
++
bc
;
}
}
*
bigcells
=
bc
;
j
=
bc
/
3
;
h
=
1
;
do
h
=
3
*
h
+
1
;
while
(
h
<
j
);
do
/* shell sort */
{
for
(
i
=
h
;
i
<
bc
;
++
i
)
{
st
=
cellstart
[
i
];
si
=
cellsize
[
i
];
for
(
j
=
i
;
cellsize
[
j
-
h
]
>
si
||
(
cellsize
[
j
-
h
]
==
si
&&
cellstart
[
j
-
h
]
>
st
);
)
{
cellsize
[
j
]
=
cellsize
[
j
-
h
];
cellstart
[
j
]
=
cellstart
[
j
-
h
];
if
((
j
-=
h
)
<
h
)
break
;
}
cellsize
[
j
]
=
si
;
cellstart
[
j
]
=
st
;
}
h
/=
3
;
}
while
(
h
>
0
);
}
/*****************************************************************************
* *
* celltrips() assigns to each vertex v a value depending on the set of *
* weights w(v,v1,v2), where w(v,v1,v2) depends on the number of vertices *
* adjacent to an odd number of {v,v1,v2}. {v,v1,v2} are constrained to *
* belong to the same cell. We try the cells in increasing order of size, *
* and stop as soon as any cell splits. *
* *
*****************************************************************************/
void
celltrips
(
graph
*
g
,
int
*
lab
,
int
*
ptn
,
int
level
,
int
numcells
,
int
tvpos
,
int
*
invar
,
int
invararg
,
boolean
digraph
,
int
m
,
int
n
)
{
int
i
,
pc
;
setword
sw
;
set
*
gw
;
int
wt
;
int
v
,
iv
,
v1
,
iv1
,
v2
,
iv2
;
int
icell
,
bigcells
,
cell1
,
cell2
;
int
*
cellstart
,
*
cellsize
;
set
*
gv
;
#if !MAXN
DYNALLOC1
(
set
,
workset
,
workset_sz
,
m
,
"celltrips"
);
DYNALLOC1
(
int
,
workshort
,
workshort_sz
,
n
+
2
,
"celltrips"
);
#endif
for
(
i
=
n
;
--
i
>=
0
;)
invar
[
i
]
=
0
;
cellstart
=
workshort
;
cellsize
=
workshort
+
(
n
/
2
);
getbigcells
(
ptn
,
level
,
3
,
&
bigcells
,
cellstart
,
cellsize
,
n
);
for
(
icell
=
0
;
icell
<
bigcells
;
++
icell
)
{
cell1
=
cellstart
[
icell
];
cell2
=
cell1
+
cellsize
[
icell
]
-
1
;
for
(
iv
=
cell1
;
iv
<=
cell2
-
2
;
++
iv
)
{
v
=
lab
[
iv
];
gv
=
GRAPHROW
(
g
,
v
,
m
);
for
(
iv1
=
iv
+
1
;
iv1
<=
cell2
-
1
;
++
iv1
)
{
v1
=
lab
[
iv1
];
gw
=
GRAPHROW
(
g
,
v1
,
m
);
for
(
i
=
M
;
--
i
>=
0
;)
workset
[
i
]
=
gv
[
i
]
^
gw
[
i
];
for
(
iv2
=
iv1
+
1
;
iv2
<=
cell2
;
++
iv2
)
{
v2
=
lab
[
iv2
];
gw
=
GRAPHROW
(
g
,
v2
,
m
);
pc
=
0
;
for
(
i
=
M
;
--
i
>=
0
;)
if
((
sw
=
workset
[
i
]
^
gw
[
i
])
!=
0
)
pc
+=
POPCOUNT
(
sw
);
wt
=
FUZZ1
(
pc
);
ACCUM
(
invar
[
v
],
wt
);
ACCUM
(
invar
[
v1
],
wt
);
ACCUM
(
invar
[
v2
],
wt
);
}
}
}
wt
=
invar
[
lab
[
cell1
]];
for
(
i
=
cell1
+
1
;
i
<=
cell2
;
++
i
)
if
(
invar
[
lab
[
i
]]
!=
wt
)
return
;
}
}
/*****************************************************************************
* *
* cellquads() assigns to each vertex v a value depending on the set of *
* weights w(v,v1,v2,v3), where w(v,v1,v2,v3) depends on the number of *
* vertices adjacent to an odd number of {v,v1,v2,v3}. {v,v1,v2,v3} are *
* constrained to belong to the same cell. We try the cells in increasing *
* order of size, and stop as soon as any cell splits. *
* *
*****************************************************************************/
void
cellquads
(
graph
*
g
,
int
*
lab
,
int
*
ptn
,
int
level
,
int
numcells
,
int
tvpos
,
int
*
invar
,
int
invararg
,
boolean
digraph
,
int
m
,
int
n
)
{
int
i
,
pc
;
setword
sw
;
set
*
gw
;
int
wt
;
int
v
,
iv
,
v1
,
iv1
,
v2
,
iv2
,
v3
,
iv3
;
int
icell
,
bigcells
,
cell1
,
cell2
;
int
*
cellstart
,
*
cellsize
;
set
*
gv
;
#if !MAXN
DYNALLOC1
(
set
,
workset
,
workset_sz
,
m
,
"cellquads"
);
DYNALLOC1
(
int
,
workshort
,
workshort_sz
,
n
+
2
,
"cellquads"
);
DYNALLOC1
(
set
,
ws1
,
ws1_sz
,
m
,
"cellquads"
);
#endif
for
(
i
=
n
;
--
i
>=
0
;)
invar
[
i
]
=
0
;
cellstart
=
workshort
;
cellsize
=
workshort
+
(
n
/
2
);
getbigcells
(
ptn
,
level
,
4
,
&
bigcells
,
cellstart
,
cellsize
,
n
);
for
(
icell
=
0
;
icell
<
bigcells
;
++
icell
)
{
cell1
=
cellstart
[
icell
];
cell2
=
cell1
+
cellsize
[
icell
]
-
1
;
for
(
iv
=
cell1
;
iv
<=
cell2
-
3
;
++
iv
)
{
v
=
lab
[
iv
];
gv
=
GRAPHROW
(
g
,
v
,
m
);
for
(
iv1
=
iv
+
1
;
iv1
<=
cell2
-
2
;
++
iv1
)
{
v1
=
lab
[
iv1
];
gw
=
GRAPHROW
(
g
,
v1
,
m
);
for
(
i
=
M
;
--
i
>=
0
;)
workset
[
i
]
=
gv
[
i
]
^
gw
[
i
];
for
(
iv2
=
iv1
+
1
;
iv2
<=
cell2
-
1
;
++
iv2
)
{
v2
=
lab
[
iv2
];
gw
=
GRAPHROW
(
g
,
v2
,
m
);
for
(
i
=
M
;
--
i
>=
0
;)
ws1
[
i
]
=
workset
[
i
]
^
gw
[
i
];
for
(
iv3
=
iv2
+
1
;
iv3
<=
cell2
;
++
iv3
)
{
v3
=
lab
[
iv3
];
gw
=
GRAPHROW
(
g
,
v3
,
m
);
pc
=
0
;
for
(
i
=
M
;
--
i
>=
0
;)
if
((
sw
=
ws1
[
i
]
^
gw
[
i
])
!=
0
)
pc
+=
POPCOUNT
(
sw
);
wt
=
FUZZ1
(
pc
);
ACCUM
(
invar
[
v
],
wt
);
ACCUM
(
invar
[
v1
],
wt
);
ACCUM
(
invar
[
v2
],
wt
);
ACCUM
(
invar
[
v3
],
wt
);
}
}
}
}
wt
=
invar
[
lab
[
cell1
]];
for
(
i
=
cell1
+
1
;
i
<=
cell2
;
++
i
)
if
(
invar
[
lab
[
i
]]
!=
wt
)
return
;
}
}
/*****************************************************************************
* *
* cellquins() assigns to each vertex v a value depending on the set of *
* weights w(v,v1,v2,v3,v4), where w(v,v1,v2,v3,v4) depends on the number *
* of vertices adjacent to an odd number of {v,v1,v2,v3,v4}. *
* {v,v1,v2,v3,v4} are constrained to belong to the same cell. We try the *
* cells in increasing order of size, and stop as soon as any cell splits. *
* *
*****************************************************************************/
void
cellquins
(
graph
*
g
,
int
*
lab
,
int
*
ptn
,
int
level
,
int
numcells
,
int
tvpos
,
int
*
invar
,
int
invararg
,
boolean
digraph
,
int
m
,
int
n
)
{
int
i
,
pc
;
setword
sw
;
set
*
gw
;
int
wt
;
int
v
,
iv
,
v1
,
iv1
,
v2
,
iv2
,
v3
,
iv3
,
v4
,
iv4
;
int
icell
,
bigcells
,
cell1
,
cell2
;
int
*
cellstart
,
*
cellsize
;
set
*
gv
;
#if !MAXN
DYNALLOC1
(
set
,
workset
,
workset_sz
,
m
,
"cellquins"
);
DYNALLOC1
(
int
,
workshort
,
workshort_sz
,
n
+
2
,
"cellquins"
);
DYNALLOC1
(
set
,
ws1
,
ws1_sz
,
m
,
"cellquins"
);
DYNALLOC1
(
set
,
ws2
,
ws2_sz
,
m
,
"cellquins"
);
#endif
for
(
i
=
n
;
--
i
>=
0
;)
invar
[
i
]
=
0
;
cellstart
=
workshort
;
cellsize
=
workshort
+
(
n
/
2
);
getbigcells
(
ptn
,
level
,
5
,
&
bigcells
,
cellstart
,
cellsize
,
n
);
for
(
icell
=
0
;
icell
<
bigcells
;
++
icell
)
{
cell1
=
cellstart
[
icell
];
cell2
=
cell1
+
cellsize
[
icell
]
-
1
;
for
(
iv
=
cell1
;
iv
<=
cell2
-
4
;
++
iv
)
{
v
=
lab
[
iv
];
gv
=
GRAPHROW
(
g
,
v
,
m
);
for
(
iv1
=
iv
+
1
;
iv1
<=
cell2
-
3
;
++
iv1
)
{
v1
=
lab
[
iv1
];
gw
=
GRAPHROW
(
g
,
v1
,
m
);
for
(
i
=
M
;
--
i
>=
0
;)
workset
[
i
]
=
gv
[
i
]
^
gw
[
i
];
for
(
iv2
=
iv1
+
1
;
iv2
<=
cell2
-
2
;
++
iv2
)
{
v2
=
lab
[
iv2
];
gw
=
GRAPHROW
(
g
,
v2
,
m
);
for
(
i
=
M
;
--
i
>=
0
;)
ws1
[
i
]
=
workset
[
i
]
^
gw
[
i
];
for
(
iv3
=
iv2
+
1
;
iv3
<=
cell2
-
1
;
++
iv3
)
{
v3
=
lab
[
iv3
];
gw
=
GRAPHROW
(
g
,
v3
,
m
);
for
(
i
=
M
;
--
i
>=
0
;)
ws2
[
i
]
=
ws1
[
i
]
^
gw
[
i
];
for
(
iv4
=
iv3
+
1
;
iv4
<=
cell2
;
++
iv4
)
{
v4
=
lab
[
iv4
];
gw
=
GRAPHROW
(
g
,
v4
,
m
);
pc
=
0
;
for
(
i
=
M
;
--
i
>=
0
;)
if
((
sw
=
ws2
[
i
]
^
gw
[
i
])
!=
0
)
pc
+=
POPCOUNT
(
sw
);
wt
=
FUZZ1
(
pc
);
ACCUM
(
invar
[
v
],
wt
);
ACCUM
(
invar
[
v1
],
wt
);
ACCUM
(
invar
[
v2
],
wt
);
ACCUM
(
invar
[
v3
],
wt
);
ACCUM
(
invar
[
v4
],
wt
);
}
}
}
}
}
wt
=
invar
[
lab
[
cell1
]];
for
(
i
=
cell1
+
1
;
i
<=
cell2
;
++
i
)
if
(
invar
[
lab
[
i
]]
!=
wt
)
return
;
}
}
/*****************************************************************************
* *
* uniqinter(s1,s2,m) returns the number in both sets if it is unique, *
* or -1 if there is none or it is not unique. *
*****************************************************************************/
static
int
uniqinter
(
set
*
s1
,
set
*
s2
,
int
m
)
{
int
i
,
j
;
setword
w
;
for
(
i
=
0
;
i
<
M
;
++
i
)
{
if
((
w
=
s1
[
i
]
&
s2
[
i
])
!=
0
)
{
j
=
FIRSTBITNZ
(
w
);
if
(
w
!=
BITT
[
j
])
return
-1
;
j
+=
TIMESWORDSIZE
(
i
);
for
(
++
i
;
i
<
M
;
++
i
)
if
(
s1
[
i
]
&
s2
[
i
])
return
-1
;
return
j
;
}
}
return
-1
;
}
/*****************************************************************************
* *
* cellfano2() assigns to each vertex v a value depending on the set of *
* weights w(v,v1,v2,v3), where w(v,v1,v2,v3) depends on the number of *
* fano-plane analogues containing {v,v1,v2,v3}. {v,v1,v2,v3} are *
* constrained to belong to the same cell and being independent and *
* non-collinear. We try the cells in increasing order of size, and stop *
* as soon as any cell splits. *
* *
*****************************************************************************/
void
cellfano2
(
graph
*
g
,
int
*
lab
,
int
*
ptn
,
int
level
,
int
numcells
,
int
tvpos
,
int
*
invar
,
int
invararg
,
boolean
digraph
,
int
m
,
int
n
)
{
int
i
,
pc
;
setword
sw
;
int
wt
;
int
v0
,
v1
,
v2
,
v3
,
iv0
,
iv1
,
iv2
,
iv3
;
int
icell
,
bigcells
,
cell1
,
cell2
;
int
*
cellstart
,
*
cellsize
;
int
nw
,
x01
,
x02
,
x03
,
x12
,
x13
,
x23
;
int
pnt0
,
pnt1
,
pnt2
;
set
*
gv0
,
*
gv1
,
*
gv2
,
*
gv3
;
set
*
gp0
,
*
gp1
,
*
gp2
;
#if !MAXN
DYNALLOC1
(
int
,
workshort
,
workshort_sz
,
n
+
2
,
"cellfano2"
);
DYNALLOC1
(
int
,
vv
,
vv_sz
,
n
,
"cellfano2"
);
DYNALLOC1
(
int
,
ww
,
ww_sz
,
n
,
"cellfano2"
);
#endif
for
(
i
=
n
;
--
i
>=
0
;)
invar
[
i
]
=
0
;
cellstart
=
workshort
;
cellsize
=
workshort
+
(
n
/
2
);
getbigcells
(
ptn
,
level
,
4
,
&
bigcells
,
cellstart
,
cellsize
,
n
);
for
(
icell
=
0
;
icell
<
bigcells
;
++
icell
)
{
cell1
=
cellstart
[
icell
];
cell2
=
cell1
+
cellsize
[
icell
]
-
1
;
for
(
iv0
=
cell1
;
iv0
<=
cell2
-
3
;
++
iv0
)
{
v0
=
lab
[
iv0
];
gv0
=
GRAPHROW
(
g
,
v0
,
m
);
nw
=
0
;
for
(
iv1
=
iv0
+
1
;
iv1
<=
cell2
;
++
iv1
)
{
v1
=
lab
[
iv1
];
if
(
ISELEMENT
(
gv0
,
v1
))
continue
;
if
((
x01
=
uniqinter
(
gv0
,
GRAPHROW
(
g
,
v1
,
m
),
m
))
<
0
)
continue
;
vv
[
nw
]
=
v1
;
ww
[
nw
]
=
x01
;
++
nw
;
}
for
(
iv1
=
0
;
iv1
<
nw
-2
;
++
iv1
)
{
v1
=
vv
[
iv1
];
gv1
=
GRAPHROW
(
g
,
v1
,
m
);
x01
=
ww
[
iv1
];
for
(
iv2
=
iv1
+
1
;
iv2
<
nw
-1
;
++
iv2
)
{
x02
=
ww
[
iv2
];
if
(
x02
==
x01
)
continue
;
v2
=
vv
[
iv2
];
if
(
ISELEMENT
(
gv1
,
v2
))
continue
;
gv2
=
GRAPHROW
(
g
,
v2
,
m
);
if
((
x12
=
uniqinter
(
gv1
,
gv2
,
m
))
<
0
)
continue
;
for
(
iv3
=
iv2
+
1
;
iv3
<
nw
;
++
iv3
)
{
x03
=
ww
[
iv3
];
if
(
x03
==
x01
||
x03
==
x02
)
continue
;
v3
=
vv
[
iv3
];
if
(
ISELEMENT
(
gv1
,
v3
)
||
ISELEMENT
(
gv2
,
v3
))
continue
;
gv3
=
GRAPHROW
(
g
,
v3
,
m
);
if
((
x13
=
uniqinter
(
gv1
,
gv3
,
m
))
<
0
)
continue
;
if
((
x23
=
uniqinter
(
gv2
,
gv3
,
m
))
<
0
||
x23
==
x13
)
continue
;
if
((
pnt0
=
uniqinter
(
GRAPHROW
(
g
,
x01
,
m
),
GRAPHROW
(
g
,
x23
,
m
),
m
))
<
0
)
continue
;
if
((
pnt1
=
uniqinter
(
GRAPHROW
(
g
,
x02
,
m
),
GRAPHROW
(
g
,
x13
,
m
),
m
))
<
0
)
continue
;
if
((
pnt2
=
uniqinter
(
GRAPHROW
(
g
,
x03
,
m
),
GRAPHROW
(
g
,
x12
,
m
),
m
))
<
0
)
continue
;
gp0
=
GRAPHROW
(
g
,
pnt0
,
m
);
gp1
=
GRAPHROW
(
g
,
pnt1
,
m
);
gp2
=
GRAPHROW
(
g
,
pnt2
,
m
);
pc
=
0
;
for
(
i
=
M
;
--
i
>=
0
;)
{
sw
=
gp0
[
i
]
&
gp1
[
i
]
&
gp2
[
i
];
if
(
sw
)
pc
+=
POPCOUNT
(
sw
);
}
wt
=
FUZZ1
(
pc
);
ACCUM
(
invar
[
v0
],
wt
);
ACCUM
(
invar
[
v1
],
wt
);
ACCUM
(
invar
[
v2
],
wt
);
ACCUM
(
invar
[
v3
],
wt
);
}
}
}
}
wt
=
invar
[
lab
[
cell1
]];
for
(
i
=
cell1
+
1
;
i
<=
cell2
;
++
i
)
if
(
invar
[
lab
[
i
]]
!=
wt
)
return
;
}
}
/*****************************************************************************
* *
* setnbhd(g,m,n,w,wn) is an auxiliary routine that sets wn to the union *
* of the neighbours of the vertices in w. *
* *
*****************************************************************************/
void
setnbhd
(
graph
*
g
,
int
m
,
int
n
,
set
*
w
,
set
*
wn
)
{
int
i
,
j
;
set
*
gi
;
i
=
nextelement
(
w
,
M
,
-1
);
if
(
i
<
0
)
{
EMPTYSET
(
wn
,
M
);
return
;
}
gi
=
GRAPHROW
(
g
,
i
,
M
);
for
(
j
=
M
;
--
j
>=
0
;)
wn
[
j
]
=
gi
[
j
];
while
((
i
=
nextelement
(
w
,
M
,
i
))
>=
0
)
{
gi
=
GRAPHROW
(
g
,
i
,
M
);
for
(
j
=
M
;
--
j
>=
0
;)
wn
[
j
]
|=
gi
[
j
];
}
}
/*****************************************************************************
* *
* cellfano() assigns to each vertex v a value depending on the set of *
* weights w(v,v1,v2,v3), where w(v,v1,v2,v3) depends on the number of *
* fano-plane analogues containing {v,v1,v2,v3}. {v,v1,v2,v3} are *
* constrained to belong to the same cell and being independent. We try *
* the cells in increasing order of size, and stop as soon as any cell *
* splits. *
* *
*****************************************************************************/
void
cellfano
(
graph
*
g
,
int
*
lab
,
int
*
ptn
,
int
level
,
int
numcells
,
int
tvpos
,
int
*
invar
,
int
invararg
,
boolean
digraph
,
int
m
,
int
n
)
{
int
i
,
pc
;
setword
sw
;
int
wt
;
int
v0
,
v1
,
v2
,
v3
,
iv0
,
iv1
,
iv2
,
iv3
;
int
icell
,
bigcells
,
cell1
,
cell2
;
int
*
cellstart
,
*
cellsize
;
set
*
gv0
,
*
gv1
,
*
gv2
,
*
gv3
;
#if !MAXN
DYNALLOC1
(
int
,
workshort
,
workshort_sz
,
n
+
2
,
"cellfano"
);
DYNALLOC1
(
set
,
w01
,
w01_sz
,
m
,
"cellfano"
);
DYNALLOC1
(
set
,
w02
,
w02_sz
,
m
,
"cellfano"
);
DYNALLOC1
(
set
,
w03
,
w03_sz
,
m
,
"cellfano"
);
DYNALLOC1
(
set
,
w12
,
w12_sz
,
m
,
"cellfano"
);
DYNALLOC1
(
set
,
w13
,
w13_sz
,
m
,
"cellfano"
);
DYNALLOC1
(
set
,
w23
,
w23_sz
,
m
,
"cellfano"
);
DYNALLOC1
(
set
,
pt0
,
pt0_sz
,
m
,
"cellfano"
);
DYNALLOC1
(
set
,
pt1
,
pt1_sz
,
m
,
"cellfano"
);
DYNALLOC1
(
set
,
pt2
,
pt2_sz
,
m
,
"cellfano"
);
DYNALLOC1
(
set
,
workset
,
workset_sz
,
m
,
"cellfano"
);
#else
#endif
for
(
i
=
n
;
--
i
>=
0
;)
invar
[
i
]
=
0
;
cellstart
=
workshort
;
cellsize
=
workshort
+
(
n
/
2
);
getbigcells
(
ptn
,
level
,
4
,
&
bigcells
,
cellstart
,
cellsize
,
n
);
for
(
icell
=
0
;
icell
<
bigcells
;
++
icell
)
{
cell1
=
cellstart
[
icell
];
cell2
=
cell1
+
cellsize
[
icell
]
-
1
;
for
(
iv0
=
cell1
;
iv0
<=
cell2
-
3
;
++
iv0
)
{
v0
=
lab
[
iv0
];
gv0
=
GRAPHROW
(
g
,
v0
,
m
);
for
(
iv1
=
iv0
+
1
;
iv1
<=
cell2
-
2
;
++
iv1
)
{
v1
=
lab
[
iv1
];
if
(
ISELEMENT
(
gv0
,
v1
))
continue
;
gv1
=
GRAPHROW
(
g
,
v1
,
m
);
for
(
i
=
M
;
--
i
>=
0
;)
workset
[
i
]
=
gv0
[
i
]
&
gv1
[
i
];
setnbhd
(
g
,
m
,
n
,
workset
,
w01
);
for
(
iv2
=
iv1
+
1
;
iv2
<=
cell2
-
1
;
++
iv2
)
{
v2
=
lab
[
iv2
];
if
(
ISELEMENT
(
gv0
,
v2
)
||
ISELEMENT
(
gv1
,
v2
))
continue
;
gv2
=
GRAPHROW
(
g
,
v2
,
m
);
for
(
i
=
M
;
--
i
>=
0
;)
workset
[
i
]
=
gv0
[
i
]
&
gv2
[
i
];
setnbhd
(
g
,
m
,
n
,
workset
,
w02
);
for
(
i
=
M
;
--
i
>=
0
;)
workset
[
i
]
=
gv1
[
i
]
&
gv2
[
i
];
setnbhd
(
g
,
m
,
n
,
workset
,
w12
);
for
(
iv3
=
iv2
+
1
;
iv3
<=
cell2
;
++
iv3
)
{
v3
=
lab
[
iv3
];
if
(
ISELEMENT
(
gv0
,
v3
)
||
ISELEMENT
(
gv1
,
v3
)
||
ISELEMENT
(
gv2
,
v3
))
continue
;
gv3
=
GRAPHROW
(
g
,
v3
,
m
);
for
(
i
=
M
;
--
i
>=
0
;)
workset
[
i
]
=
gv0
[
i
]
&
gv3
[
i
];
setnbhd
(
g
,
m
,
n
,
workset
,
w03
);
for
(
i
=
M
;
--
i
>=
0
;)
workset
[
i
]
=
gv1
[
i
]
&
gv3
[
i
];
setnbhd
(
g
,
m
,
n
,
workset
,
w13
);
for
(
i
=
M
;
--
i
>=
0
;)
workset
[
i
]
=
gv2
[
i
]
&
gv3
[
i
];
setnbhd
(
g
,
m
,
n
,
workset
,
w23
);
for
(
i
=
M
;
--
i
>=
0
;)
workset
[
i
]
=
w01
[
i
]
&
w23
[
i
];
setnbhd
(
g
,
m
,
n
,
workset
,
pt0
);
for
(
i
=
M
;
--
i
>=
0
;)
workset
[
i
]
=
w03
[
i
]
&
w12
[
i
];
setnbhd
(
g
,
m
,
n
,
workset
,
pt1
);
for
(
i
=
M
;
--
i
>=
0
;)
workset
[
i
]
=
w02
[
i
]
&
w13
[
i
];
setnbhd
(
g
,
m
,
n
,
workset
,
pt2
);
pc
=
0
;
for
(
i
=
M
;
--
i
>=
0
;)
{
sw
=
pt0
[
i
]
&
pt1
[
i
]
&
pt2
[
i
];
if
(
sw
)
pc
+=
POPCOUNT
(
sw
);
}
wt
=
FUZZ1
(
pc
);
ACCUM
(
invar
[
v0
],
wt
);
ACCUM
(
invar
[
v1
],
wt
);
ACCUM
(
invar
[
v2
],
wt
);
ACCUM
(
invar
[
v3
],
wt
);
}
}
}
}
wt
=
invar
[
lab
[
cell1
]];
for
(
i
=
cell1
+
1
;
i
<=
cell2
;
++
i
)
if
(
invar
[
lab
[
i
]]
!=
wt
)
return
;
}
}
/*****************************************************************************
* *
* distances() assigns to each vertex v a value depending on the number of *
* vertices at each distance from v, and what cells they lie in. *
* If we find any cell which is split in this manner, we don't try any *
* further cells. *
* *
*****************************************************************************/
void
distances
(
graph
*
g
,
int
*
lab
,
int
*
ptn
,
int
level
,
int
numcells
,
int
tvpos
,
int
*
invar
,
int
invararg
,
boolean
digraph
,
int
m
,
int
n
)
{
int
i
;
set
*
gw
;
int
wt
;
int
d
,
dlim
,
cell1
,
cell2
,
iv
,
v
,
w
;
boolean
success
;
#if !MAXN
DYNALLOC1
(
set
,
workset
,
workset_sz
,
m
,
"distances"
);
DYNALLOC1
(
int
,
workshort
,
workshort_sz
,
n
+
2
,
"distances"
);
DYNALLOC1
(
set
,
ws1
,
ws1_sz
,
m
,
"distances"
);
DYNALLOC1
(
set
,
ws2
,
ws2_sz
,
m
,
"distances"
);
#endif
for
(
i
=
n
;
--
i
>=
0
;)
invar
[
i
]
=
0
;
wt
=
1
;
for
(
i
=
0
;
i
<
n
;
++
i
)
{
workshort
[
lab
[
i
]]
=
FUZZ1
(
wt
);
if
(
ptn
[
i
]
<=
level
)
++
wt
;
}
if
(
invararg
>
n
||
invararg
==
0
)
dlim
=
n
;
else
dlim
=
invararg
+
1
;
success
=
FALSE
;
for
(
cell1
=
0
;
cell1
<
n
;
cell1
=
cell2
+
1
)
{
for
(
cell2
=
cell1
;
ptn
[
cell2
]
>
level
;
++
cell2
)
{}
if
(
cell2
==
cell1
)
continue
;
for
(
iv
=
cell1
;
iv
<=
cell2
;
++
iv
)
{
v
=
lab
[
iv
];
EMPTYSET
(
ws1
,
m
);
ADDELEMENT
(
ws1
,
v
);
EMPTYSET
(
ws2
,
m
);
ADDELEMENT
(
ws2
,
v
);
for
(
d
=
1
;
d
<
dlim
;
++
d
)
{
EMPTYSET
(
workset
,
m
);
wt
=
0
;
w
=
-1
;
while
((
w
=
nextelement
(
ws2
,
M
,
w
))
>=
0
)
{
gw
=
GRAPHROW
(
g
,
w
,
m
);
ACCUM
(
wt
,
workshort
[
w
]);
for
(
i
=
M
;
--
i
>=
0
;)
workset
[
i
]
|=
gw
[
i
];
}
if
(
wt
==
0
)
break
;
ACCUM
(
wt
,
d
);
wt
=
FUZZ2
(
wt
);
ACCUM
(
invar
[
v
],
wt
);
for
(
i
=
M
;
--
i
>=
0
;)
{
ws2
[
i
]
=
workset
[
i
]
&
~
ws1
[
i
];
ws1
[
i
]
|=
ws2
[
i
];
}
}
if
(
invar
[
v
]
!=
invar
[
lab
[
cell1
]])
success
=
TRUE
;
}
if
(
success
)
break
;
}
}
/*****************************************************************************
* *
* indsets() assigns to each vertex v a value depending on which cells the *
* vertices which join v in an independent set lie in. The size of the *
* independent sets which are used is the smallest of invararg and MAXCLIQUE.*
* *
*****************************************************************************/
void
indsets
(
graph
*
g
,
int
*
lab
,
int
*
ptn
,
int
level
,
int
numcells
,
int
tvpos
,
int
*
invar
,
int
invararg
,
boolean
digraph
,
int
m
,
int
n
)
{
int
i
;
int
wt
;
set
*
gv
;
int
ss
,
setsize
;
int
v
[
MAXCLIQUE
];
long
wv
[
MAXCLIQUE
];
set
*
s0
,
*
s1
;
#if !MAXN
DYNALLOC1
(
int
,
workshort
,
workshort_sz
,
n
+
2
,
"indsets"
);
DYNALLOC2
(
set
,
wss
,
wss_sz
,
m
,
MAXCLIQUE
-1
,
"indsets"
);
#endif
for
(
i
=
n
;
--
i
>=
0
;)
invar
[
i
]
=
0
;
if
(
invararg
<=
1
||
digraph
)
return
;
if
(
invararg
>
MAXCLIQUE
)
setsize
=
MAXCLIQUE
;
else
setsize
=
invararg
;
wt
=
1
;
for
(
i
=
0
;
i
<
n
;
++
i
)
{
workshort
[
lab
[
i
]]
=
FUZZ2
(
wt
);
if
(
ptn
[
i
]
<=
level
)
++
wt
;
}
for
(
v
[
0
]
=
0
;
v
[
0
]
<
n
;
++
v
[
0
])
{
wv
[
0
]
=
workshort
[
v
[
0
]];
s0
=
(
set
*
)
wss
;
EMPTYSET
(
s0
,
m
);
for
(
i
=
v
[
0
]
+
1
;
i
<
n
;
++
i
)
ADDELEMENT
(
s0
,
i
);
gv
=
GRAPHROW
(
g
,
v
[
0
],
m
);
for
(
i
=
M
;
--
i
>=
0
;)
s0
[
i
]
&=
~
gv
[
i
];
ss
=
1
;
v
[
1
]
=
v
[
0
];
while
(
ss
>
0
)
{
if
(
ss
==
setsize
)
{
wt
=
FUZZ1
(
wv
[
ss
-1
]);
for
(
i
=
ss
;
--
i
>=
0
;)
ACCUM
(
invar
[
v
[
i
]],
wt
);
--
ss
;
}
else
if
((
v
[
ss
]
=
nextelement
((
set
*
)
wss
+
M
*
(
ss
-1
),
M
,
v
[
ss
]))
<
0
)
--
ss
;
else
{
wv
[
ss
]
=
wv
[
ss
-1
]
+
workshort
[
v
[
ss
]];
++
ss
;
if
(
ss
<
setsize
)
{
gv
=
GRAPHROW
(
g
,
v
[
ss
-1
],
m
);
s1
=
(
set
*
)
wss
+
M
*
(
ss
-2
);
for
(
i
=
M
;
--
i
>=
0
;)
s1
[
i
+
M
]
=
s1
[
i
]
&
~
gv
[
i
];
v
[
ss
]
=
v
[
ss
-1
];
}
}
}
}
}
/*****************************************************************************
* *
* cliques() assigns to each vertex v a value depending on which cells the *
* vertices which join v in a clique lie in. The size of the cliques used *
* is the smallest of invararg and MAXCLIQUE. *
* *
*****************************************************************************/
void
cliques
(
graph
*
g
,
int
*
lab
,
int
*
ptn
,
int
level
,
int
numcells
,
int
tvpos
,
int
*
invar
,
int
invararg
,
boolean
digraph
,
int
m
,
int
n
)
{
int
i
;
int
wt
;
set
*
gv
;
int
ss
,
setsize
;
int
v
[
MAXCLIQUE
];
long
wv
[
MAXCLIQUE
];
set
*
ns
;
#if !MAXN
DYNALLOC1
(
int
,
workshort
,
workshort_sz
,
n
+
2
,
"cliques"
);
DYNALLOC2
(
set
,
wss
,
wss_sz
,
m
,
MAXCLIQUE
-1
,
"cliques"
);
#else
set
wss
[
MAXCLIQUE
-1
][
MAXM
];
#endif
for
(
i
=
n
;
--
i
>=
0
;)
invar
[
i
]
=
0
;
if
(
invararg
<=
1
||
digraph
)
return
;
if
(
invararg
>
MAXCLIQUE
)
setsize
=
MAXCLIQUE
;
else
setsize
=
invararg
;
wt
=
1
;
for
(
i
=
0
;
i
<
n
;
++
i
)
{
workshort
[
lab
[
i
]]
=
FUZZ2
(
wt
);
if
(
ptn
[
i
]
<=
level
)
++
wt
;
}
for
(
v
[
0
]
=
0
;
v
[
0
]
<
n
;
++
v
[
0
])
{
wv
[
0
]
=
workshort
[
v
[
0
]];
gv
=
GRAPHROW
(
g
,
v
[
0
],
m
);
ns
=
(
set
*
)
wss
;
for
(
i
=
M
;
--
i
>=
0
;)
ns
[
i
]
=
gv
[
i
];
ss
=
1
;
v
[
1
]
=
v
[
0
];
while
(
ss
>
0
)
{
if
(
ss
==
setsize
)
{
wt
=
FUZZ1
(
wv
[
ss
-1
]);
for
(
i
=
ss
;
--
i
>=
0
;)
ACCUM
(
invar
[
v
[
i
]],
wt
);
--
ss
;
}
else
if
((
v
[
ss
]
=
nextelement
((
set
*
)
wss
+
M
*
(
ss
-1
),
M
,
v
[
ss
]))
<
0
)
--
ss
;
else
{
wv
[
ss
]
=
wv
[
ss
-1
]
+
workshort
[
v
[
ss
]];
++
ss
;
if
(
ss
<
setsize
)
{
gv
=
GRAPHROW
(
g
,
v
[
ss
-1
],
m
);
ns
=
(
set
*
)
wss
+
M
*
(
ss
-2
);
for
(
i
=
M
;
--
i
>=
0
;)
ns
[
i
+
M
]
=
ns
[
i
]
&
gv
[
i
];
v
[
ss
]
=
v
[
ss
-1
];
}
}
}
}
}
/*****************************************************************************
* *
* cellcliq() assigns to each vertex v a value depending on the number of *
* cliques which v lies in and which lie in the same cell as v. The size *
* of clique counted is the smallest of invararg and MAXCLIQUE. We try the *
* cells in increasing order of size and stop as soon as any cell splits. *
* *
*****************************************************************************/
void
cellcliq
(
graph
*
g
,
int
*
lab
,
int
*
ptn
,
int
level
,
int
numcells
,
int
tvpos
,
int
*
invar
,
int
invararg
,
boolean
digraph
,
int
m
,
int
n
)
{
int
i
;
int
wt
;
set
*
gv
;
int
ss
,
setsize
;
int
v
[
MAXCLIQUE
];
set
*
ns
;
int
*
cellstart
,
*
cellsize
;
int
iv
,
icell
,
bigcells
,
cell1
,
cell2
;
int
pc
;
setword
sw
;
#if !MAXN
DYNALLOC1
(
set
,
workset
,
workset_sz
,
m
,
"cellcliq"
);
DYNALLOC1
(
int
,
workshort
,
workshort_sz
,
n
+
2
,
"cellcliq"
);
DYNALLOC2
(
set
,
wss
,
wss_sz
,
m
,
MAXCLIQUE
-1
,
"cellcliq"
);
#endif
for
(
i
=
n
;
--
i
>=
0
;)
invar
[
i
]
=
0
;
if
(
invararg
<=
1
||
digraph
)
return
;
if
(
invararg
>
MAXCLIQUE
)
setsize
=
MAXCLIQUE
;
else
setsize
=
invararg
;
cellstart
=
workshort
;
cellsize
=
workshort
+
(
n
/
2
);
getbigcells
(
ptn
,
level
,
setsize
>
6
?
setsize
:
6
,
&
bigcells
,
cellstart
,
cellsize
,
n
);
for
(
icell
=
0
;
icell
<
bigcells
;
++
icell
)
{
cell1
=
cellstart
[
icell
];
cell2
=
cell1
+
cellsize
[
icell
]
-
1
;
EMPTYSET
(
workset
,
m
);
for
(
iv
=
cell1
;
iv
<=
cell2
;
++
iv
)
ADDELEMENT
(
workset
,
lab
[
iv
]);
for
(
iv
=
cell1
;
iv
<=
cell2
;
++
iv
)
{
v
[
0
]
=
lab
[
iv
];
gv
=
GRAPHROW
(
g
,
v
[
0
],
m
);
ns
=
(
set
*
)
wss
;
pc
=
0
;
for
(
i
=
M
;
--
i
>=
0
;)
{
ns
[
i
]
=
gv
[
i
]
&
workset
[
i
];
if
((
sw
=
ns
[
i
])
!=
0
)
pc
+=
POPCOUNT
(
sw
);
}
if
(
pc
<=
1
||
pc
>=
cellsize
[
icell
]
-
2
)
continue
;
ss
=
1
;
v
[
1
]
=
v
[
0
];
while
(
ss
>
0
)
{
if
(
ss
==
setsize
)
{
for
(
i
=
ss
;
--
i
>=
0
;)
++
invar
[
v
[
i
]];
--
ss
;
}
else
if
((
v
[
ss
]
=
nextelement
((
set
*
)
wss
+
M
*
(
ss
-1
),
M
,
v
[
ss
]))
<
0
)
--
ss
;
else
{
++
ss
;
if
(
ss
<
setsize
)
{
gv
=
GRAPHROW
(
g
,
v
[
ss
-1
],
m
);
ns
=
(
set
*
)
wss
+
M
*
(
ss
-2
);
for
(
i
=
M
;
--
i
>=
0
;)
ns
[
i
+
M
]
=
ns
[
i
]
&
gv
[
i
];
v
[
ss
]
=
v
[
ss
-1
];
}
}
}
}
wt
=
invar
[
lab
[
cell1
]];
for
(
iv
=
cell1
+
1
;
iv
<=
cell2
;
++
iv
)
if
(
invar
[
lab
[
iv
]]
!=
wt
)
return
;
}
}
/*****************************************************************************
* *
* cellind() assigns to each vertex v a value depending on the number of *
* independent sets which v lies in and which lie in the same cell as v. *
* The size of clique counted is the smallest of invararg and MAXCLIQUE. *
* We try the cells in increasing order of size and stop as soon as any *
* cell splits. *
* *
*****************************************************************************/
void
cellind
(
graph
*
g
,
int
*
lab
,
int
*
ptn
,
int
level
,
int
numcells
,
int
tvpos
,
int
*
invar
,
int
invararg
,
boolean
digraph
,
int
m
,
int
n
)
{
int
i
;
int
wt
;
set
*
gv
;
int
ss
,
setsize
;
int
v
[
MAXCLIQUE
];
set
*
ns
;
int
*
cellstart
,
*
cellsize
;
int
iv
,
icell
,
bigcells
,
cell1
,
cell2
;
int
pc
;
setword
sw
;
#if !MAXN
DYNALLOC1
(
set
,
workset
,
workset_sz
,
m
,
"cellind"
);
DYNALLOC1
(
int
,
workshort
,
workshort_sz
,
n
+
2
,
"cellind"
);
DYNALLOC2
(
set
,
wss
,
wss_sz
,
m
,
MAXCLIQUE
-1
,
"cellind"
);
#endif
for
(
i
=
n
;
--
i
>=
0
;)
invar
[
i
]
=
0
;
if
(
invararg
<=
1
||
digraph
)
return
;
if
(
invararg
>
MAXCLIQUE
)
setsize
=
MAXCLIQUE
;
else
setsize
=
invararg
;
cellstart
=
workshort
;
cellsize
=
workshort
+
(
n
/
2
);
getbigcells
(
ptn
,
level
,
setsize
>
6
?
setsize
:
6
,
&
bigcells
,
cellstart
,
cellsize
,
n
);
for
(
icell
=
0
;
icell
<
bigcells
;
++
icell
)
{
cell1
=
cellstart
[
icell
];
cell2
=
cell1
+
cellsize
[
icell
]
-
1
;
EMPTYSET
(
workset
,
m
);
for
(
iv
=
cell1
;
iv
<=
cell2
;
++
iv
)
ADDELEMENT
(
workset
,
lab
[
iv
]);
for
(
iv
=
cell1
;
iv
<=
cell2
;
++
iv
)
{
v
[
0
]
=
lab
[
iv
];
gv
=
GRAPHROW
(
g
,
v
[
0
],
m
);
ns
=
(
set
*
)
wss
;
pc
=
0
;
for
(
i
=
M
;
--
i
>=
0
;)
{
ns
[
i
]
=
~
gv
[
i
]
&
workset
[
i
];
if
((
sw
=
ns
[
i
])
!=
0
)
pc
+=
POPCOUNT
(
sw
);
}
if
(
pc
<=
1
||
pc
>=
cellsize
[
icell
]
-
2
)
continue
;
ss
=
1
;
v
[
1
]
=
v
[
0
];
while
(
ss
>
0
)
{
if
(
ss
==
setsize
)
{
for
(
i
=
ss
;
--
i
>=
0
;)
++
invar
[
v
[
i
]];
--
ss
;
}
else
if
((
v
[
ss
]
=
nextelement
((
set
*
)
wss
+
M
*
(
ss
-1
),
M
,
v
[
ss
]))
<
0
)
--
ss
;
else
{
++
ss
;
if
(
ss
<
setsize
)
{
gv
=
GRAPHROW
(
g
,
v
[
ss
-1
],
m
);
ns
=
(
set
*
)
wss
+
M
*
(
ss
-2
);
for
(
i
=
M
;
--
i
>=
0
;)
ns
[
i
+
M
]
=
ns
[
i
]
&
~
gv
[
i
];
v
[
ss
]
=
v
[
ss
-1
];
}
}
}
}
wt
=
invar
[
lab
[
cell1
]];
for
(
iv
=
cell1
+
1
;
iv
<=
cell2
;
++
iv
)
if
(
invar
[
lab
[
iv
]]
!=
wt
)
return
;
}
}
/*****************************************************************************
* *
* adjacencies() assigns to each vertex v a code depending on which cells *
* it is joined to and from, and how many times. It is intended to provide *
* better partitioning that the normal refinement routine for digraphs. *
* It will not help with undirected graphs in nauty at all. *
* *
*****************************************************************************/
void
adjacencies
(
graph
*
g
,
int
*
lab
,
int
*
ptn
,
int
level
,
int
numcells
,
int
tvpos
,
int
*
invar
,
int
invararg
,
boolean
digraph
,
int
m
,
int
n
)
{
int
i
,
v
,
w
;
int
vwt
,
wwt
;
set
*
gv
;
#if !MAXN
DYNALLOC1
(
int
,
workshort
,
workshort_sz
,
n
+
2
,
"adjacencies"
);
#endif
vwt
=
1
;
for
(
i
=
0
;
i
<
n
;
++
i
)
{
workshort
[
lab
[
i
]]
=
vwt
;
if
(
ptn
[
i
]
<=
level
)
++
vwt
;
invar
[
i
]
=
0
;
}
for
(
v
=
0
,
gv
=
(
set
*
)
g
;
v
<
n
;
++
v
,
gv
+=
M
)
{
vwt
=
FUZZ1
(
workshort
[
v
]);
wwt
=
0
;
w
=
-1
;
while
((
w
=
nextelement
(
gv
,
M
,
w
))
>=
0
)
{
ACCUM
(
wwt
,
FUZZ2
(
workshort
[
w
]));
ACCUM
(
invar
[
w
],
vwt
);
}
ACCUM
(
invar
[
v
],
wwt
);
}
}
/*****************************************************************************
* *
* nautinv_check() checks that this file is compiled compatibly with the *
* given parameters. If not, call exit(1). *
* *
*****************************************************************************/
void
nautinv_check
(
int
wordsize
,
int
m
,
int
n
,
int
version
)
{
if
(
wordsize
!=
WORDSIZE
)
{
fprintf
(
ERRFILE
,
"Error: WORDSIZE mismatch in nautinv.c
\n
"
);
exit
(
1
);
}
#if MAXN
if
(
m
>
MAXM
)
{
fprintf
(
ERRFILE
,
"Error: MAXM inadequate in nautinv.c
\n
"
);
exit
(
1
);
}
if
(
n
>
MAXN
)
{
fprintf
(
ERRFILE
,
"Error: MAXN inadequate in nautinv.c
\n
"
);
exit
(
1
);
}
#endif
if
(
version
<
NAUTYREQUIRED
)
{
fprintf
(
ERRFILE
,
"Error: nautinv.c version mismatch
\n
"
);
exit
(
1
);
}
}
/*****************************************************************************
* *
* nautinv_freedyn() - free the dynamic memory in this module *
* *
*****************************************************************************/
void
nautinv_freedyn
(
void
)
{
#if !MAXN
DYNFREE
(
workset
,
workset_sz
);
DYNFREE
(
workshort
,
workshort_sz
);
DYNFREE
(
ws1
,
ws1_sz
);
DYNFREE
(
ws2
,
ws2_sz
);
DYNFREE
(
vv
,
vv_sz
);
DYNFREE
(
ww
,
ww_sz
);
DYNFREE
(
w01
,
w01_sz
);
DYNFREE
(
w02
,
w02_sz
);
DYNFREE
(
w03
,
w03_sz
);
DYNFREE
(
w12
,
w12_sz
);
DYNFREE
(
w13
,
w13_sz
);
DYNFREE
(
w23
,
w23_sz
);
DYNFREE
(
pt0
,
pt0_sz
);
DYNFREE
(
pt1
,
pt1_sz
);
DYNFREE
(
pt2
,
pt2_sz
);
DYNFREE
(
wss
,
wss_sz
);
#endif
}
/*===================================================================*/
/*****************************************************************************
* *
* semirefine(g,lab,ptn,level,numcells,strength,active,m,n) performs a *
* refinement operation on the partition at the specified level of the *
* partition nest (lab,ptn). *numcells is assumed to contain the number of *
* cells on input, and is updated. The initial set of active cells (alpha *
* in the paper) is specified in the set active. Precisely, x is in active *
* iff the cell starting at index x in lab is active. *
* *code is set to a value which depends on the fine detail of the *
* algorithm, but which is independent of the labelling of the graph. *
* *
*****************************************************************************/
static
int
semirefine
(
graph
*
g
,
int
*
lab
,
int
*
ptn
,
int
level
,
int
*
numcells
,
int
strength
,
set
*
active
,
int
m
,
int
n
)
{
int
i
,
c1
,
c2
,
labc1
;
setword
x
;
set
*
set1
,
*
set2
;
int
split1
,
split2
,
cell1
,
cell2
;
int
cnt
,
bmin
,
bmax
;
long
longcode
;
set
*
gptr
;
int
maxcell
,
maxpos
,
hint
;
#if !MAXN
DYNALLOC1
(
int
,
workperm
,
workperm_sz
,
n
,
"refine"
);
DYNALLOC1
(
set
,
workset
,
workset_sz
,
m
,
"refine"
);
DYNALLOC1
(
int
,
bucket
,
bucket_sz
,
n
+
2
,
"refine"
);
DYNALLOC1
(
int
,
count
,
count_sz
,
n
,
"refine"
);
#endif
longcode
=
*
numcells
;
split1
=
-1
;
hint
=
0
;
while
(
*
numcells
<
n
&&
((
split1
=
hint
,
ISELEMENT
(
active
,
split1
))
||
(
split1
=
nextelement
(
active
,
M
,
split1
))
>=
0
||
(
split1
=
nextelement
(
active
,
M
,
-1
))
>=
0
))
{
DELELEMENT
(
active
,
split1
);
for
(
split2
=
split1
;
ptn
[
split2
]
>
level
;
++
split2
)
{}
longcode
=
MASH
(
longcode
,
split1
+
split2
);
if
(
split1
==
split2
)
/* trivial splitting cell */
{
gptr
=
GRAPHROW
(
g
,
lab
[
split1
],
M
);
for
(
cell1
=
0
;
cell1
<
n
;
cell1
=
cell2
+
1
)
{
for
(
cell2
=
cell1
;
ptn
[
cell2
]
>
level
;
++
cell2
)
{}
if
(
cell1
==
cell2
)
continue
;
c1
=
cell1
;
c2
=
cell2
;
while
(
c1
<=
c2
)
{
labc1
=
lab
[
c1
];
if
(
ISELEMENT
(
gptr
,
labc1
))
++
c1
;
else
{
lab
[
c1
]
=
lab
[
c2
];
lab
[
c2
]
=
labc1
;
--
c2
;
}
}
if
(
c2
>=
cell1
&&
c1
<=
cell2
)
{
ptn
[
c2
]
=
level
;
longcode
=
MASH
(
longcode
,
FUZZ1
(
c2
));
++*
numcells
;
if
(
ISELEMENT
(
active
,
cell1
)
||
c2
-
cell1
>=
cell2
-
c1
)
{
ADDELEMENT
(
active
,
c1
);
if
(
c1
==
cell2
)
hint
=
c1
;
}
else
{
ADDELEMENT
(
active
,
cell1
);
if
(
c2
==
cell1
)
hint
=
cell1
;
}
}
}
}
else
/* nontrivial splitting cell */
{
EMPTYSET
(
workset
,
m
);
for
(
i
=
split1
;
i
<=
split2
;
++
i
)
ADDELEMENT
(
workset
,
lab
[
i
]);
longcode
=
MASH
(
longcode
,
FUZZ2
(
split2
-
split1
+
1
));
for
(
cell1
=
0
;
cell1
<
n
;
cell1
=
cell2
+
1
)
{
for
(
cell2
=
cell1
;
ptn
[
cell2
]
>
level
;
++
cell2
)
{}
if
(
cell1
==
cell2
)
continue
;
i
=
cell1
;
set1
=
workset
;
set2
=
GRAPHROW
(
g
,
lab
[
i
],
m
);
cnt
=
0
;
for
(
c1
=
m
;
--
c1
>=
0
;)
if
((
x
=
((
*
set1
++
)
&
(
*
set2
++
)))
!=
0
)
cnt
+=
POPCOUNT
(
x
);
count
[
i
]
=
bmin
=
bmax
=
cnt
;
bucket
[
cnt
]
=
1
;
while
(
++
i
<=
cell2
)
{
set1
=
workset
;
set2
=
GRAPHROW
(
g
,
lab
[
i
],
m
);
cnt
=
0
;
for
(
c1
=
m
;
--
c1
>=
0
;)
if
((
x
=
((
*
set1
++
)
&
(
*
set2
++
)))
!=
0
)
cnt
+=
POPCOUNT
(
x
);
while
(
bmin
>
cnt
)
bucket
[
--
bmin
]
=
0
;
while
(
bmax
<
cnt
)
bucket
[
++
bmax
]
=
0
;
++
bucket
[
cnt
];
count
[
i
]
=
cnt
;
}
if
(
bmin
==
bmax
)
{
longcode
=
MASH
(
longcode
,
FUZZ1
(
bmin
+
cell1
));
continue
;
}
c1
=
cell1
;
maxcell
=
-1
;
for
(
i
=
bmin
;
i
<=
bmax
;
++
i
)
if
(
bucket
[
i
])
{
c2
=
c1
+
bucket
[
i
];
bucket
[
i
]
=
c1
;
longcode
=
MASH
(
longcode
,
i
+
c1
);
if
(
c2
-
c1
>
maxcell
)
{
maxcell
=
c2
-
c1
;
maxpos
=
c1
;
}
if
(
c1
!=
cell1
)
{
ADDELEMENT
(
active
,
c1
);
if
(
c2
-
c1
==
1
)
hint
=
c1
;
++*
numcells
;
}
if
(
c2
<=
cell2
)
ptn
[
c2
-1
]
=
level
;
c1
=
c2
;
}
for
(
i
=
cell1
;
i
<=
cell2
;
++
i
)
workperm
[
bucket
[
count
[
i
]]
++
]
=
lab
[
i
];
for
(
i
=
cell1
;
i
<=
cell2
;
++
i
)
lab
[
i
]
=
workperm
[
i
];
if
(
!
ISELEMENT
(
active
,
cell1
))
{
ADDELEMENT
(
active
,
cell1
);
DELELEMENT
(
active
,
maxpos
);
/* check maxpos is alwas defined */
}
}
}
if
(
--
strength
==
0
)
break
;
/* negative is fine! */
}
longcode
=
MASH
(
longcode
,
FUZZ2
(
*
numcells
));
return
CLEANUP
(
longcode
);
}
void
refinvar
(
graph
*
g
,
int
*
lab
,
int
*
ptn
,
int
level
,
int
numcells
,
int
tvpos
,
int
*
invar
,
int
invararg
,
boolean
digraph
,
int
m
,
int
n
)
{
int
i
,
j
;
int
wt
;
int
icell
,
bigcells
,
cell1
,
cell2
;
int
*
cellstart
,
*
cellsize
;
int
newnumcells
;
#if !MAXN
DYNALLOC1
(
int
,
workshort
,
workshort_sz
,
n
+
2
,
"refinvar"
);
DYNALLOC1
(
int
,
vv
,
vv_sz
,
n
,
"refinvar"
);
DYNALLOC1
(
int
,
ww
,
ww_sz
,
n
,
"refinvar"
);
DYNALLOC1
(
set
,
ws1
,
ws1_sz
,
n
,
"refinvar"
);
#endif
for
(
i
=
n
;
--
i
>=
0
;)
invar
[
i
]
=
0
;
cellstart
=
workshort
;
cellsize
=
workshort
+
(
n
/
2
);
getbigcells
(
ptn
,
level
,
2
,
&
bigcells
,
cellstart
,
cellsize
,
n
);
for
(
icell
=
0
;
icell
<
bigcells
;
++
icell
)
{
cell1
=
cellstart
[
icell
];
cell2
=
cell1
+
cellsize
[
icell
]
-
1
;
for
(
i
=
cell1
;
i
<=
cell2
;
++
i
)
{
for
(
j
=
0
;
j
<
n
;
++
j
)
{
vv
[
j
]
=
lab
[
j
];
ww
[
j
]
=
ptn
[
j
];
}
newnumcells
=
numcells
+
1
;
ww
[
cell1
]
=
level
;
EMPTYSET
(
ws1
,
m
);
ADDELEMENT
(
ws1
,
cell1
);
vv
[
i
]
=
lab
[
cell1
];
vv
[
cell1
]
=
lab
[
i
];
invar
[
lab
[
i
]]
=
semirefine
(
g
,
vv
,
ww
,
level
,
&
newnumcells
,
invararg
,
ws1
,
m
,
n
);
}
wt
=
invar
[
lab
[
cell1
]];
for
(
i
=
cell1
+
1
;
i
<=
cell2
;
++
i
)
if
(
invar
[
lab
[
i
]]
!=
wt
)
return
;
}
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Tue, Oct 27, 3:44 PM (1 d, 1 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
406199
Default Alt Text
nautinv.c (64 KB)
Attached To
Mode
R272 SoC_NEM_Synthesis
Attached
Detach File
Event Timeline