Initialize:
PROC = {
InitVertex:
PROC [ra:
REF
ANY]
RETURNS [stop:
BOOL] = {
v: Vertex ← NARROW[ra];
stop ← FALSE;
IF v.unique OR v.QNext # notInQ THEN ERROR;
EnQ[v]};
hts: CARDINAL ← MAX[MinHashSize, Real.RoundC[sizeFactor * (vertices[A].Size[] + vertices[B].Size[])]];
QFirst ← endOfQ; QCount ← 0;
hashTable ← NEW [HashTableRep[hts]];
hashTable.firstNonEmpty ← NullIndex;
FOR hti: HashTableIndex
IN [0 .. hashTable.length)
DO
hashTable[hti] ← [];
ENDLOOP;
vertices[A].EnumerateIncreasing[InitVertex];
vertices[B].EnumerateIncreasing[InitVertex];
nonUniqueCount[A] ← vertices[A].Size[];
nonUniqueCount[B] ← vertices[B].Size[];
IF QCount # (nonUniqueCount[A] + nonUniqueCount[B]) THEN ERROR;
};
SetQToAllNonUniques:
PROC = {
AddVertex:
PROC [ra:
REF
ANY]
RETURNS [stop:
BOOL] = {
v: Vertex ← NARROW[ra];
stop ← FALSE;
IF v.QNext # notInQ THEN ERROR;
EnQ[v]};
wasAll ← TRUE;
vertices[A].EnumerateIncreasing[AddVertex];
vertices[B].EnumerateIncreasing[AddVertex];
IF QCount # (nonUniqueCount[A] + nonUniqueCount[B]) THEN ERROR;
hashTable.firstNonEmpty ← NullIndex};
ChoosePairs:
PROC [useSuspects:
BOOL]
RETURNS [pairCount:
CARDINAL] = {
wasAll ← TRUE; pairCount ← 0;
FOR hti: HashTableIndex ← hashTable.firstNonEmpty, hashTable[hti].nextNonEmpty
WHILE hti # NullIndex
DO
first: ARRAY GraphID OF Vertex ← [NIL, NIL];
IF hashTable[hti].suspect # useSuspects THEN LOOP;
FOR v: Vertex ← hashTable[hti].v, v.colorNext
WHILE v #
NIL
DO
IF v.QNext # notInQ THEN ERROR;
IF first[v.graph] = NIL THEN first[v.graph] ← v;
ENDLOOP;
IF first[
A]#
NIL
AND first[
B]#
NIL
THEN {
IF first[A].unique # first[B].unique THEN ERROR;
IF
NOT first[
A].unique
THEN {
pairCount ← pairCount + 1;
EnQ[first[A]]; EnQ[first[B]]}};
ENDLOOP;
hashTable.firstNonEmpty ← NullIndex};
WHILE nonUniqueCount[
A]#0
AND nonUniqueCount[
B]#0
DO
mcCount: CARDINAL ← 0;
someMC: BOOL ← FALSE;
pass ← pass + 1;
WHILE QFirst # endOfQ
DO
v: Vertex ← QFirst;
oldColor: Color ← v.oldColor;
newColor: Color ← v.curColor ← ComputeColor[v];
IF QFirst = notInQ THEN ERROR;
QFirst ← v.QNext;
v.QNext ← notInQ;
IF wasAll
AND
NOT someMC
THEN {
IF hashTable[oldColor].newColor = noColor THEN hashTable[oldColor].newColor ← newColor
ELSE IF hashTable[oldColor].multicolored THEN ERROR
ELSE IF hashTable[oldColor].newColor = newColor THEN NULL
ELSE hashTable[oldColor].multicolored ← someMC ← TRUE;
};
IF hashTable[newColor].count[
A] = 0
AND hashTable[newColor].count[
B] = 0
THEN {
hashTable[newColor].v ← NIL;
hashTable[newColor].nextNonEmpty ← hashTable.firstNonEmpty;
hashTable.firstNonEmpty ← newColor};
v.colorNext ← hashTable[newColor].v;
hashTable[newColor].v ← v;
hashTable[newColor].count[v.graph] ← hashTable[newColor].count[v.graph] + 1;
ENDLOOP;
QCount ← 0;
FOR hti: HashTableIndex ← hashTable.firstNonEmpty, hashTable[hti].nextNonEmpty
WHILE hti # NullIndex
DO
uniques: ARRAY GraphID OF BOOL = [hashTable[hti].count[A]=1, hashTable[hti].count[B]=1];
unique: BOOL ← uniques[A] AND uniques[B];
IF unique
THEN {
a: Vertex ← hashTable[hti].v;
b: Vertex ← a.colorNext;
IF b.colorNext # NIL THEN ERROR;
IF a.graph = b.graph THEN ERROR;
IF a.unique OR b.unique THEN ERROR;
a.unique ← b.unique ← TRUE;
a.equiv ← b; b.equiv ← a;
nonUniqueCount[A] ← nonUniqueCount[A] - 1;
nonUniqueCount[B] ← nonUniqueCount[B] - 1;
};
ENDLOOP;
FOR hti: HashTableIndex ← hashTable.firstNonEmpty, hashTable[hti].nextNonEmpty
WHILE hti # NullIndex
DO
uniques: ARRAY GraphID OF BOOL = [hashTable[hti].count[A]=1, hashTable[hti].count[B]=1];
unique: BOOL ← uniques[A] AND uniques[B];
IF unique
THEN {
a: Vertex ← hashTable[hti].v;
b: Vertex ← a.colorNext;
IF b.colorNext # NIL THEN ERROR;
IF a.graph = b.graph THEN ERROR;
IF NOT (a.unique AND b.unique) THEN ERROR;
AddFrontier[a]; AddFrontier[b];
};
hashTable[hti].suspect← hashTable[hti].count[A] # hashTable[hti].count[B];
FOR v: Vertex ← hashTable[hti].v, v.colorNext
WHILE v #
NIL
DO
v.oldColor ← v.curColor;
v.suspect ← hashTable[hti].suspect;
ENDLOOP;
hashTable[hti].count[A] ← 0;
hashTable[hti].count[B] ← 0;
hashTable[hti].newColor ← noColor;
hashTable[hti].multicolored ← FALSE;
ENDLOOP;
WriteAll[IO.PutFR["Almost end of pass %g", IO.card[pass]], vertices, hashTable];
Log["QCount=%g, nonUniqueCount=[%g, %g], someMC=%g, wasAll=%g\n",
IO.card[QCount], IO.card[nonUniqueCount[A]],
IO.card[nonUniqueCount[B]], IO.bool[someMC], IO.bool[wasAll]];
WriteQ[QFirst];
IF QCount > 0
THEN {
wasAll ← (nonUniqueCount[A] + nonUniqueCount[B]) = QCount;
hashTable.firstNonEmpty ← NullIndex}
ELSE IF someMC OR (NOT wasAll) THEN SetQToAllNonUniques[]
ELSE {pairCount:
CARDINAL ← ChoosePairs[useSuspects:
FALSE];
IF pairCount = 0
THEN {QFirst ← endOfQ; QCount ← 0;
pairCount ← ChoosePairs[useSuspects: TRUE];
IF pairCount = 0 THEN EXIT}};
ENDLOOP;