if (kbm_print_level >= 3)
printf(" #Calling fsa_genmult2_short.\n"); if (!genmultptr->flags[DFA]) {
fprintf(stderr, "Error: fsa_genmult2 only applies to DFA's.\n"); return0;
}
if (genmultptr->alphabet->type != PRODUCT ||
genmultptr->alphabet->arity != 2) {
fprintf(stderr, "Error in fsa_genmult2: fsa must be 2-variable.\n"); return0;
}
if (genmultptr->states->type != LABELED) {
fprintf(stderr, "Error in fsa_genmult2: states of fsa must be labeled.\n"); return0;
}
keeptable = stringlen(genmult2filename) > 0; if (readback && !keeptable) {
fprintf(stderr, "Error in fsa_genmult2: readback true but empty filename.\n"); return0;
}
short_hash_init(&ht, FALSE, 0, 0, 0);
ht_ptr = ht.current_ptr;
ht_ptr[0] = genmultptr->initial[1];
ht_ptr[1] = genmultptr->initial[1];
im = short_hash_locate(&ht, 2); /* Each state in the composite transition table will be represented as a *subsetofthesetoforderedpairsofstatesof*genmultptr.Theinitial *statecontainsjustonesuchpair,ofwhichbothcomponentsaretheinitial *stateof*genmultptr.Thesubsetswillbestoredasvariable-lengthrecords *inthehash-table,asalistofpairsinincreasingorder.Ifastateis *reachedfromatransition($,x)or(x,$)(with$thepaddingsymbol),then *itneedstobemarkedassuch,sincewedonotallowa$tobefollowedby *anyothergenerator.Wedothisbyaddinga1ora2totheendofthe *statelist-thisisrecognisablebythefactthatthelengthofthe *statelistthenbecomesodd.
*/ if (im != 1) {
fprintf(stderr, "Hash-initialisation problem in fsa_genmult2.\n"); return0;
} if (keeptable) if ((tablefile = fopen(genmult2filename, "w")) == 0) {
fprintf(stderr, "Error: cannot open file %s\n", genmult2filename); return0;
} if (dense_op)
tmalloc(fsarow, int, ne) else tmalloc(fsarow, int, 2 * ne + 1)
label = genmultptr->states->setToLabels;
cstate = 0; if (dense_op)
len = ne; /* The length of the fsarow output. */
nt = 0; /* Number of transitions in genmult2ptr */
if (dense_op) for (i = 0; i < ne; i++)
fsarow[i] = 0; else
len = 0;
e = 0; /* e is the edge number of generator pair (g1,g3) */ for (g1 = 1; g1 <= ngens1; g1++) for (g3 = 1; g3 <= ngens1; g3++) { /* Calculate action of pair (g1,g3) on state cstate - to get the image, *wehavetoapply((g1,g2),(g2,g3))toeachorderedpairinthe *subsetcorrespondingtocstate,*andthisforeachgeneratorg2of *thebase-alphabet(includingthepaddingsymbol).
*/
es1 = ngens * ngens1 + 1;
ef1 = ngens1 * ngens1 - 1; for (cstate = ns; cstate >= 1; cstate--) { /* We work backwards through the states, since we wish to add on additional *elementsattheendofthelistinthehash-table-thisdestroys *laterentries,butthatdoesn'tmatter,sincewehavealreadydealt *withthem.
*/
cs_ptr = short_hash_rec(&ht, cstate);
reclen = short_hash_rec_len(&ht, cstate); if (reclen % 2 == 1)
reclen--; /* The last entry only marks the fact that this is a "padded state"*/
cs_ptre = short_hash_rec(&ht, cstate) + reclen - 1; /* Apply generators ( ($,g2), (g2,$) ) and see if we get anything new. *Wewon'tbotherabouthavingtheminincreasingorderthistime.
*/
ptr = cs_ptr; while (ptr <= cs_ptre) {
csa = *(ptr++);
csb = *(ptr++); for (e1 = es1, e2 = ngens1; e1 <= ef1; e1++, e2 += ngens1) {
csima = target(dense_ip, table, e1, csa, dr); if (csima == 0) continue;
csimb = target(dense_ip, table, e2, csb, dr); if (csimb == 0) continue; /* see if (csima,csimb) is new */
ht_chptr = cs_ptr;
got = FALSE; while (ht_chptr < cs_ptre) { if (csima == ht_chptr[0] && csimb == ht_chptr[1]) {
got = TRUE; break;
}
ht_chptr += 2;
} if (!got) { /* add (csima,csimb) to the end */
*(++cs_ptre) = csima;
*(++cs_ptre) = csimb;
}
}
} /* Now we see which pairs in the subset are of form (s,t), where s is *anacceptstateforageneratora,andtforageneratorb. *Thelistofallsuchpairs(a,b)willformthelabelofthestate,which *willbethelistofwords[a1*b1,a2*b2,..,ar*br],withthe(ai,bi)coming *inlex-order.
*/
ht_ptrb = labelht.current_ptr;
ht_ptre = ht_ptrb - 1;
ptr = cs_ptr; while (ptr <= cs_ptre) {
csa = *(ptr++);
csb = *(ptr++); if (((l1 = label[csa]) != 0) && ((l2 = label[csb]) != 0)) {
labellist1 = genmultptr->states->labels->wordslist[l1];
labellist2 = genmultptr->states->labels->wordslist[l2];
j1 = 0; while (labellist1[j1]) {
g1 = labellist1[j1][0]; if (g1 == 0)
g1 = ngens1;
j2 = 0; while (labellist2[j2]) {
genmult2ptr->is_accepting[cstate] = TRUE;
g2 = labellist2[j2][0]; if (g2 == 0)
g2 = ngens1; if (ht_ptrb > ht_ptre || g1 > *(ht_ptre - 1) ||
(g1 == *(ht_ptre - 1) && g2 > *ht_ptre)) { /* We have a new generator pair to be added to the end */
*(++ht_ptre) = g1;
*(++ht_ptre) = g2;
} else {
ht_chptr = ht_ptrb; while (*ht_chptr < g1)
ht_chptr += 2; while (*ht_chptr == g1 && *(ht_chptr + 1) < g2)
ht_chptr += 2; if (g1 < *ht_chptr || g2 < *(ht_chptr + 1)) { /* we have a new generator pair to be added in the middle */
ht_ptr = ht_ptre;
ht_ptre += 2; while (ht_ptr >= ht_chptr) {
*(ht_ptr + 2) = *ht_ptr;
ht_ptr--;
}
*ht_chptr = g1;
*(ht_chptr + 1) = g2;
}
}
j2++;
}
j1++;
}
}
} /* That completes the calculation of the label for cstate */
newlabel[cstate] = short_hash_locate(&labelht, ht_ptre - ht_ptrb + 1);
}
short_hash_clear(&ht);
ct = 0; for (i = 1; i <= ns; i++) if (genmult2ptr->is_accepting[i])
ct++;
genmult2ptr->num_accepting = ct; if (ct == 1 || ct != ns) {
tmalloc(genmult2ptr->accepting, int, ct + 1);
ct = 0; for (i = 1; i <= ns; i++) if (genmult2ptr->is_accepting[i])
genmult2ptr->accepting[++ct] = i;
}
tfree(genmult2ptr->is_accepting);
tfree(genmultptr->is_accepting);
/* Finally copy the records from the label hash-table into the set of labels
*/
nlab = labelset->size = labelht.num_recs; if (kbm_print_level >= 3)
printf(" #There are %d distinct labels.\n", nlab);
tmalloc(labelset->wordslist, gen **, nlab + 1); for (i = 1; i <= nlab; i++) {
len = short_hash_rec_len(&labelht, i) / 2;
tmalloc(labelset->wordslist[i], gen *, len + 1);
ht_ptr = short_hash_rec(&labelht, i); for (j = 0; j < len; j++) {
tmalloc(labelset->wordslist[i][j], gen, 3);
labelset->wordslist[i][j][0] = ht_ptr[2 * j];
labelset->wordslist[i][j][1] = ht_ptr[2 * j + 1];
labelset->wordslist[i][j][2] = 0;
}
labelset->wordslist[i][len] = 0;
}
short_hash_clear(&labelht); if (destroy)
fsa_clear(genmultptr);
if (kbm_print_level >= 3)
printf(" #Calling fsa_genmult2_int.\n"); if (!genmultptr->flags[DFA]) {
fprintf(stderr, "Error: fsa_genmult2 only applies to DFA's.\n"); return0;
}
if (genmultptr->alphabet->type != PRODUCT ||
genmultptr->alphabet->arity != 2) {
fprintf(stderr, "Error in fsa_genmult2: fsa must be 2-variable.\n"); return0;
}
if (genmultptr->states->type != LABELED) {
fprintf(stderr, "Error in fsa_genmult2: states of fsa must be labeled.\n"); return0;
}
keeptable = stringlen(genmult2filename) > 0; if (readback && !keeptable) {
fprintf(stderr, "Error in fsa_genmult2: readback true but empty filename.\n"); return0;
}
hash_init(&ht, FALSE, 0, 0, 0);
ht_ptr = ht.current_ptr;
ht_ptr[0] = genmultptr->initial[1];
ht_ptr[1] = genmultptr->initial[1];
im = hash_locate(&ht, 2); /* Each state in the composite transition table will be represented as a *subsetofthesetoforderedpairsofstatesof*genmultptr.Theinitial *statecontainsjustonesuchpair,ofwhichbothcomponentsaretheinitial *stateof*genmultptr.Thesubsetswillbestoredasvariable-lengthrecords *inthehash-table,asalistofpairsinincreasingorder.Ifastateis *reachedfromatransition($,x)or(x,$)(with$thepaddingsymbol),then *itneedstobemarkedassuch,sincewedonotallowa$tobefollowedby *anyothergenerator.Wedothisbyaddinga1ora2totheendofthe *statelist-thisisrecognisablebythefactthatthelengthofthe *statelistthenbecomesodd.
*/ if (im != 1) {
fprintf(stderr, "Hash-initialisation problem in fsa_genmult2.\n"); return0;
} if (keeptable) if ((tablefile = fopen(genmult2filename, "w")) == 0) {
fprintf(stderr, "Error: cannot open file %s\n", genmult2filename); return0;
} if (dense_op)
tmalloc(fsarow, int, ne) else tmalloc(fsarow, int, 2 * ne + 1)
label = genmultptr->states->setToLabels;
cstate = 0; if (dense_op)
len = ne; /* The length of the fsarow output. */
nt = 0; /* Number of transitions in genmult2ptr */
if (dense_op) for (i = 0; i < ne; i++)
fsarow[i] = 0; else
len = 0;
e = 0; /* e is the edge number of generator pair (g1,g3) */ for (g1 = 1; g1 <= ngens1; g1++) for (g3 = 1; g3 <= ngens1; g3++) { /* Calculate action of pair (g1,g3) on state cstate - to get the image, *wehavetoapply((g1,g2),(g2,g3))toeachorderedpairinthe *subsetcorrespondingtocstate,*andthisforeachgeneratorg2of *thebase-alphabet(includingthepaddingsymbol).
*/
es1 = ngens * ngens1 + 1;
ef1 = ngens1 * ngens1 - 1; for (cstate = ns; cstate >= 1; cstate--) { /* We work backwards through the states, since we wish to add on additional *elementsattheendofthelistinthehash-table-thisdestroys *laterentries,butthatdoesn'tmatter,sincewehavealreadydealt *withthem.
*/
cs_ptr = hash_rec(&ht, cstate);
reclen = hash_rec_len(&ht, cstate); if (reclen % 2 == 1)
reclen--; /* The last entry only marks the fact that this is a "padded state"*/
cs_ptre = hash_rec(&ht, cstate) + reclen - 1; /* Apply generators ( ($,g2), (g2,$) ) and see if we get anything new. *Wewon'tbotherabouthavingtheminincreasingorderthistime.
*/
ptr = cs_ptr; while (ptr <= cs_ptre) {
csa = *(ptr++);
csb = *(ptr++); for (e1 = es1, e2 = ngens1; e1 <= ef1; e1++, e2 += ngens1) {
csima = target(dense_ip, table, e1, csa, dr); if (csima == 0) continue;
csimb = target(dense_ip, table, e2, csb, dr); if (csimb == 0) continue; /* see if (csima,csimb) is new */
ht_chptr = cs_ptr;
got = FALSE; while (ht_chptr < cs_ptre) { if (csima == ht_chptr[0] && csimb == ht_chptr[1]) {
got = TRUE; break;
}
ht_chptr += 2;
} if (!got) { /* add (csima,csimb) to the end */
*(++cs_ptre) = csima;
*(++cs_ptre) = csimb;
}
}
} /* Now we see which pairs in the subset are of form (s,t), where s is *anacceptstateforageneratora,andtforageneratorb. *Thelistofallsuchpairs(a,b)willformthelabelofthestate,which *willbethelistofwords[a1*b1,a2*b2,..,ar*br],withthe(ai,bi)coming *inlex-order.
*/
ht_ptrb = labelht.current_ptr;
ht_ptre = ht_ptrb - 1;
ptr = cs_ptr; while (ptr <= cs_ptre) {
csa = *(ptr++);
csb = *(ptr++); if (((l1 = label[csa]) != 0) && ((l2 = label[csb]) != 0)) {
labellist1 = genmultptr->states->labels->wordslist[l1];
labellist2 = genmultptr->states->labels->wordslist[l2];
j1 = 0; while (labellist1[j1]) {
g1 = labellist1[j1][0]; if (g1 == 0)
g1 = ngens1;
j2 = 0; while (labellist2[j2]) {
genmult2ptr->is_accepting[cstate] = TRUE;
g2 = labellist2[j2][0]; if (g2 == 0)
g2 = ngens1; if (ht_ptrb > ht_ptre || g1 > *(ht_ptre - 1) ||
(g1 == *(ht_ptre - 1) && g2 > *ht_ptre)) { /* We have a new generator pair to be added to the end */
*(++ht_ptre) = g1;
*(++ht_ptre) = g2;
} else {
ht_chptr = ht_ptrb; while (*ht_chptr < g1)
ht_chptr += 2; while (*ht_chptr == g1 && *(ht_chptr + 1) < g2)
ht_chptr += 2; if (g1 < *ht_chptr || g2 < *(ht_chptr + 1)) { /* we have a new generator pair to be added in the middle */
ht_ptr = ht_ptre;
ht_ptre += 2; while (ht_ptr >= ht_chptr) {
*(ht_ptr + 2) = *ht_ptr;
ht_ptr--;
}
*ht_chptr = g1;
*(ht_chptr + 1) = g2;
}
}
j2++;
}
j1++;
}
}
} /* That completes the calculation of the label for cstate */
newlabel[cstate] = hash_locate(&labelht, ht_ptre - ht_ptrb + 1);
}
hash_clear(&ht);
ct = 0; for (i = 1; i <= ns; i++) if (genmult2ptr->is_accepting[i])
ct++;
genmult2ptr->num_accepting = ct; if (ct == 1 || ct != ns) {
tmalloc(genmult2ptr->accepting, int, ct + 1);
ct = 0; for (i = 1; i <= ns; i++) if (genmult2ptr->is_accepting[i])
genmult2ptr->accepting[++ct] = i;
}
tfree(genmult2ptr->is_accepting);
tfree(genmultptr->is_accepting);
/* Finally copy the records from the label hash-table into the set of labels
*/
nlab = labelset->size = labelht.num_recs; if (kbm_print_level >= 3)
printf(" #There are %d distinct labels.\n", nlab);
tmalloc(labelset->wordslist, gen **, nlab + 1); for (i = 1; i <= nlab; i++) {
len = hash_rec_len(&labelht, i) / 2;
tmalloc(labelset->wordslist[i], gen *, len + 1);
ht_ptr = hash_rec(&labelht, i); for (j = 0; j < len; j++) {
tmalloc(labelset->wordslist[i][j], gen, 3);
labelset->wordslist[i][j][0] = ht_ptr[2 * j];
labelset->wordslist[i][j][1] = ht_ptr[2 * j + 1];
labelset->wordslist[i][j][2] = 0;
}
labelset->wordslist[i][len] = 0;
}
hash_clear(&labelht); if (destroy)
fsa_clear(genmultptr);
/* This procedure takes the fsa *genmultptr produced by fsa_triples, *andbuildsaparticularmultiplierMult_g1. *Thismerelyinvolvessettingtheacceptstatesof*genmultptr *inaccordancewiththelabelsofitsstates. *gcanbe0,fortheidentitygenerator,which(inshortlexcase)inevitably *producesthediagonaloftheword-acceptor. *Thisprocedurealtersitsargumentsanddoesnotreturnanything.
*/ int fsa_makemult(fsa *genmultptr, int g)
{ int ngens, ns, i, j, ct;
gen **labellist;
setToLabelsType *label;
if (kbm_print_level >= 3)
printf(" #Calling fsa_makemult with generator number %d.\n", g); if (!genmultptr->flags[DFA]) {
fprintf(stderr, "Error: fsa_makemult only applies to DFA's.\n"); return -1;
}
if (genmultptr->alphabet->type != PRODUCT ||
genmultptr->alphabet->arity != 2) {
fprintf(stderr, "Error in fsa_makemult: fsa must be 2-variable.\n"); return -1;
}
if (genmultptr->states->type != LABELED) {
fprintf(stderr, "Error in fsa_makemult: states of fsa must be labeled.\n"); return -1;
}
ns = genmultptr->states->size;
ngens = genmultptr->alphabet->base->size; if (g < 0 || g > ngens + 1) {
fprintf(stderr, "#Error in fsa_makemult: Generator is out of range.\n"); return -1;
}
tfree(genmultptr->accepting);
tfree(genmultptr->is_accepting);
label = genmultptr->states->setToLabels;
ct = 0; for (i = 1; i <= ns; i++) if (label[i] > 0) {
labellist = genmultptr->states->labels->wordslist[label[i]];
j = 0; while (labellist[j]) { if (labellist[j][0] == g)
ct++;
j++;
}
}
genmultptr->num_accepting = ct; if (ct < ns || ns == 1) {
tfree(genmultptr->accepting);
tmalloc(genmultptr->accepting, int, ct + 1);
ct = 0; for (i = 1; i <= ns; i++) if (label[i] > 0) {
labellist = genmultptr->states->labels->wordslist[label[i]];
j = 0; while (labellist[j]) { if (labellist[j][0] == g)
genmultptr->accepting[++ct] = i;
j++;
}
}
} /* The state labelling is no longer relevant, so we clear it */
genmultptr->states->type = SIMPLE;
srec_clear(genmultptr->states->labels);
tfree(genmultptr->states->labels);
tfree(genmultptr->states->setToLabels); return0;
}
/* This procedure takes the fsa *genmult2ptr produced by fsa_genmult2, *andbuildsaparticularlength-2multiplierMult_g1g2. *Thismerelyinvolveslocatingtheacceptstates. *Thisprocedurealtersitsargumentsanddoesnotreturnanything.
*/ int fsa_makemult2(fsa *genmult2ptr, int g1, int g2)
{ int ngens, ns, nlabs, i, j, ct;
gen ***labellist;
boolean *accept;
setToLabelsType *labelnumber;
if (kbm_print_level >= 3)
printf(" #Calling fsa_makemult2 with generators %d and %d.\n", g1, g2); if (!genmult2ptr->flags[DFA]) {
fprintf(stderr, "Error: fsa_makemult2 only applies to DFA's.\n"); return -1;
}
if (genmult2ptr->alphabet->type != PRODUCT ||
genmult2ptr->alphabet->arity != 2) {
fprintf(stderr, "Error in fsa_makemult2: fsa must be 2-variable.\n"); return -1;
}
if (genmult2ptr->states->type != LABELED) {
fprintf(stderr, "Error in fsa_makemult2: states of fsa must be labeled.\n"); return -1;
}
if (genmult2ptr->states->labels->type != LISTOFWORDS) {
fprintf(stderr, "Error in fsa_makemult2: labels must be lists of words.\n"); return -1;
}
ns = genmult2ptr->states->size;
nlabs = genmult2ptr->states->labels->size;
ngens = genmult2ptr->states->labels->alphabet_size; if (g1 <= 0 || g1 > ngens || g2 <= 0 || g2 > ngens) {
fprintf(stderr, "#Error in fsa_makemult2: A generator is out of range.\n"); return -1;
}
tmalloc(accept, boolean, nlabs + 1);
labellist = genmult2ptr->states->labels->wordslist; /* Now we see which labels are accept-labels for the pair (g1,g2) - the *labelisanaccept-labelifthelistofwordswhichisitsname *containsg1*g2.
*/
accept[0] = FALSE; for (i = 1; i <= nlabs; i++) {
accept[i] = FALSE;
j = 0; while (labellist[i][j]) { if (labellist[i][j][0] == g1 && labellist[i][j][1] == g2) {
accept[i] = TRUE; break;
}
j++;
}
}
/* Now we can see which states are accept-states. A state is an accept-state *iffitslabelisanaccept-label. *Firstwecountthenumber.
*/
ct = 0;
labelnumber = genmult2ptr->states->setToLabels; for (i = 1; i <= ns; i++) if (accept[labelnumber[i]])
ct++;
genmult2ptr->num_accepting = ct; if (ct < ns || ns == 1) {
tfree(genmult2ptr->accepting);
tmalloc(genmult2ptr->accepting, int, ct + 1);
ct = 0; for (i = 1; i <= ns; i++) if (accept[labelnumber[i]])
genmult2ptr->accepting[++ct] = i;
}
tfree(accept);
/* The state labelling is no longer relevant, so we clear it */
genmult2ptr->states->type = SIMPLE;
srec_clear(genmult2ptr->states->labels);
tfree(genmult2ptr->states->labels);
tfree(genmult2ptr->states->setToLabels); return0;
}
/* *mult1ptr and *mult2ptr should be multiplier fsa's of an automatic group. *Thisfunctioncalculatesthecompositeofthesetwomultipliers. *Soif*mult1ptristhemutiplierforthewordw1and*mult2ptrforw2, *thenthereturnedfsaisthemultiplierforw1*w2. *Infact,*mult1ptrand*mult2ptrcanbeany2-variableautomataoverthe *samealphabet,andthecompositeisreturned.
*/
fsa *fsa_composite(fsa *mult1ptr, fsa *mult2ptr, storage_type op_table_type,
boolean destroy, char *compfilename, boolean readback)
{ if (kbm_print_level >= 3)
printf(" #Calling fsa_composite.\n"); if (mult1ptr->states->size < MAXUSHORT && mult2ptr->states->size < MAXUSHORT) return fsa_composite_short(mult1ptr, mult2ptr, op_table_type, destroy,
compfilename, readback); else return fsa_composite_int(mult1ptr, mult2ptr, op_table_type, destroy,
compfilename, readback);
}
if (kbm_print_level >= 3)
printf(" #Calling fsa_composite_short.\n"); if (!mult1ptr->flags[DFA] || !mult2ptr->flags[DFA]) {
fprintf(stderr, "Error: fsa_composite only applies to DFA's.\n"); return0;
}
if (mult1ptr->alphabet->type != PRODUCT || mult1ptr->alphabet->arity != 2) {
fprintf(stderr, "Error in fsa_composite: fsa must be 2-variable.\n"); return0;
} if (mult2ptr->alphabet->type != PRODUCT || mult2ptr->alphabet->arity != 2) {
fprintf(stderr, "Error in fsa_composite: fsa must be 2-variable.\n"); return0;
}
if (!srec_equal(mult1ptr->alphabet, mult2ptr->alphabet)) {
fprintf(stderr, "Error in fsa_composite: fsa's must have same alphabet.\n"); return0;
}
/* Locate the accept states. This is slightly cumbersome, since a state *isanacceptstateifeitherthecorrespondingsubsetcontainsa *apair(s1,s2),wheres1isandacceptstateof*mult1ptrands2an *acceptstateof*mult2ptr,orwecangetfromsomesuchstatetoan *acceptstatebyapplyingelements(($,x),(x,$). *Wewillneedtousethearraycompositeptr->is_accepting.
*/
tmalloc(compositeptr->is_accepting, boolean, ns + 1); for (i = 1; i <= ns; i++)
compositeptr->is_accepting[i] = FALSE;
ct = 0;
es1 = ngens * ngens1 + 1;
ef1 = ngens1 * ngens1 - 1; for (cstate = ns; cstate >= 1; cstate--) { /* We work backwards through the states, since we wish to add on additional *elementsattheendofthelistinthehash-table-thisdestroys *laterentries,butthatdoesn'tmatter,sincewehavealreadydealt *withthem.
*/
cs_ptr = short_hash_rec(&ht, cstate);
reclen = short_hash_rec_len(&ht, cstate); if (reclen % 2 == 1)
reclen--; /* The last entry marks the fact that this is a "padded state"*/
cs_ptre = short_hash_rec(&ht, cstate) + reclen - 1; /* First see if the set itself contains an accept-state */
ptr = cs_ptr; while (ptr <= cs_ptre) {
csa = *(ptr++);
csb = *(ptr++); if (mult1ptr->is_accepting[csa] && mult2ptr->is_accepting[csb]) {
compositeptr->is_accepting[cstate] = TRUE;
ct++; break;
}
} if (compositeptr->is_accepting[cstate]) continue; /* Next apply generators ( ($,g2), (g2,$) ) and see if we get anything new. *Wewon'tbotherabouthavingtheminincreasingorderthistime.
*/
ptr = cs_ptr; while (ptr <= cs_ptre) {
csa = *(ptr++);
csb = *(ptr++); for (e1 = es1, e2 = ngens1; e1 <= ef1; e1++, e2 += ngens1) {
csima = target(dense_ip1, table1, e1, csa, dr1); if (csima == 0) continue;
csimb = target(dense_ip2, table2, e2, csb, dr2); if (csimb == 0) continue;
/* see if (csima,csimb) is accepting */ if (mult1ptr->is_accepting[csima] && mult2ptr->is_accepting[csimb]) {
compositeptr->is_accepting[cstate] = TRUE;
ct++; break;
} /* now see if it is new */
ht_chptr = cs_ptr;
got = FALSE; while (ht_chptr < cs_ptre) { if (csima == ht_chptr[0] && csimb == ht_chptr[1]) {
got = TRUE; break;
}
ht_chptr += 2;
} if (!got) { /* add (csima,csimb) to the end */
*(++cs_ptre) = csima;
*(++cs_ptre) = csimb;
}
} if (compositeptr->is_accepting[cstate]) continue;
}
}
compositeptr->num_accepting = ct; if (ct == 1 || ct != ns) {
tmalloc(compositeptr->accepting, int, ct + 1);
ct = 0; for (i = 1; i <= ns; i++) if (compositeptr->is_accepting[i])
compositeptr->accepting[++ct] = i;
}
tfree(compositeptr->is_accepting);
tfree(mult1ptr->is_accepting);
tfree(mult2ptr->is_accepting);
short_hash_clear(&ht);
tfree(fsarow); if (destroy) {
fsa_clear(mult1ptr);
fsa_clear(mult2ptr);
}
if (kbm_print_level >= 3)
printf(" #Calling fsa_composite_int.\n"); if (!mult1ptr->flags[DFA] || !mult2ptr->flags[DFA]) {
fprintf(stderr, "Error: fsa_composite only applies to DFA's.\n"); return0;
}
if (mult1ptr->alphabet->type != PRODUCT || mult1ptr->alphabet->arity != 2) {
fprintf(stderr, "Error in fsa_composite: fsa must be 2-variable.\n"); return0;
} if (mult2ptr->alphabet->type != PRODUCT || mult2ptr->alphabet->arity != 2) {
fprintf(stderr, "Error in fsa_composite: fsa must be 2-variable.\n"); return0;
}
if (!srec_equal(mult1ptr->alphabet, mult2ptr->alphabet)) {
fprintf(stderr, "Error in fsa_composite: fsa's must have same alphabet.\n"); return0;
}
/* Locate the accept states. This is slightly cumbersome, since a state *isanacceptstateifeitherthecorrespondingsubsetcontainsa *apair(s1,s2),wheres1isandacceptstateof*mult1ptrands2an *acceptstateof*mult2ptr,orwecangetfromsomesuchstatetoan *acceptstatebyapplyingelements(($,x),(x,$). *Wewillneedtousethearraycompositeptr->is_accepting.
*/
tmalloc(compositeptr->is_accepting, boolean, ns + 1); for (i = 1; i <= ns; i++)
compositeptr->is_accepting[i] = FALSE;
ct = 0;
es1 = ngens * ngens1 + 1;
ef1 = ngens1 * ngens1 - 1; for (cstate = ns; cstate >= 1; cstate--) { /* We work backwards through the states, since we wish to add on additional *elementsattheendofthelistinthehash-table-thisdestroys *laterentries,butthatdoesn'tmatter,sincewehavealreadydealt *withthem.
*/
cs_ptr = hash_rec(&ht, cstate);
reclen = hash_rec_len(&ht, cstate); if (reclen % 2 == 1)
reclen--; /* The last entry marks the fact that this is a "padded state"*/
cs_ptre = hash_rec(&ht, cstate) + reclen - 1; /* First see if the set itself contains an accept-state */
ptr = cs_ptr; while (ptr <= cs_ptre) {
csa = *(ptr++);
csb = *(ptr++); if (mult1ptr->is_accepting[csa] && mult2ptr->is_accepting[csb]) {
compositeptr->is_accepting[cstate] = TRUE;
ct++; break;
}
} if (compositeptr->is_accepting[cstate]) continue; /* Next apply generators ( ($,g2), (g2,$) ) and see if we get anything new. *Wewon'tbotherabouthavingtheminincreasingorderthistime.
*/
ptr = cs_ptr; while (ptr <= cs_ptre) {
csa = *(ptr++);
csb = *(ptr++); for (e1 = es1, e2 = ngens1; e1 <= ef1; e1++, e2 += ngens1) {
csima = target(dense_ip1, table1, e1, csa, dr1); if (csima == 0) continue;
csimb = target(dense_ip2, table2, e2, csb, dr2); if (csimb == 0) continue;
/* see if (csima,csimb) is accepting */ if (mult1ptr->is_accepting[csima] && mult2ptr->is_accepting[csimb]) {
compositeptr->is_accepting[cstate] = TRUE;
ct++; break;
} /* now see if it is new */
ht_chptr = cs_ptr;
got = FALSE; while (ht_chptr < cs_ptre) { if (csima == ht_chptr[0] && csimb == ht_chptr[1]) {
got = TRUE; break;
}
ht_chptr += 2;
} if (!got) { /* add (csima,csimb) to the end */
*(++cs_ptre) = csima;
*(++cs_ptre) = csimb;
}
} if (compositeptr->is_accepting[cstate]) continue;
}
}
compositeptr->num_accepting = ct; if (ct == 1 || ct != ns) {
tmalloc(compositeptr->accepting, int, ct + 1);
ct = 0; for (i = 1; i <= ns; i++) if (compositeptr->is_accepting[i])
compositeptr->accepting[++ct] = i;
}
tfree(compositeptr->is_accepting);
tfree(mult1ptr->is_accepting);
tfree(mult2ptr->is_accepting);
hash_clear(&ht);
tfree(fsarow); if (destroy) {
fsa_clear(mult1ptr);
fsa_clear(mult2ptr);
}