/* gpmakesubwa.c 22/1/96. * 31/12/98 - altered to make states of type labeled, where label is * the coset rep. of coset of subgroup correspondiong to state. * 6/8/98 large scale reorganisation to omit globals, etc. * 5/2/98 change generators from type char to type `gen'. * * Build a candidate word-acceptor for those irreducible words in * a shortlex automatic group that lie in a given subgroup. * This will work, for example, for quasiconvex subgroups of * hyperbolic groups. * * SYNOPSIS: * gpmakesubwa [-w] [-kbprogcos/-diff1cos/-diff2cos] * [-diff1/-diff2/-diff1c] [-mrl maxreducelen] [-nc nochange] * [-v] [-silent] [-l] [-ms maxstates] groupname [subname] * * subname defaults to "sub". * autgroup (or equivalents) should have been run on grouname already. * groupname.subname should contain the definition of the subgroup, * in the standard format. * * Two word-reduction routines are required, one for the group elements, * and one for the cosets of the subgroup in the group. * As in wordreduce, there are four possibilities for the automaton used * to perform each of these reductions. * However, since the group will have had its automatic structure calculated * already, we always use diff_reduction for that, and do not allow * rws_reduction. * Input is from groupname.diff1, groupname.diff2 (default) or * groupname.diff1c for the reduction in the group, and * input is from groupname.wa (word-acceptor), * groupname.subname.kbprog, groupname.subname.diff1, * etc. for the coset reduction. * * The subgroup generators are input from groupname.subname, or from * groupname.subname.words, if -w is called. * (-w should be called after a run of gpchecksubwa has found words that * should be accpeted by the subgroup word-acceptor but are not.) * Output is to groupname.subname.wa. * * OPTIONS: * -diff1/diff2/diff1c * This determines which finite state automaton is used for * the word-reduction in the group. * The default is groupname.diff2. * -kbprogcos/diff1cos/diff2cos * Similar, for the coset reduction. * Input from groupname.subname.kbprog, etc. * -nc nochange * Exit when nochange words have been added to the * language of subwa, without subwa changing. * Default is 64. * -ms maxstates * At most maxstates states are allowed in the subgroup * word-acceptor being produced. Default is 32767 * represent words in the subgroup can be remembered. * Default is 32767. * -v verbose * -silent no diagnostics * -l/-h large/huge hash-tables (for big examples) * -mrl maxreducelen * To change the maximum word-length possible during reduction. * Default is 4095 *
*/
int (*reduce_word)(gen *w, reduction_struct *rs_rws); int (*reduce_word_cos)(gen *w, reduction_struct *rs_rws);
/* Functions defined in this file */ staticvoid fsa_init_subwa(fsa *subwaptr, fsa *gwaptr, gen_hash_table *coshtptr, int ngens, int maxstates); staticint calc_inv(gen *gtestword, int ngens, int *inv, reduction_struct *rsptr); staticvoid invert_word(gen *gtestword, int *inv); staticint add_word_fsa(fsa *subwaptr, int ngens, int maxstates, gen *gtestword,
gen *costestword, char **names, gen_hash_table *coshtptr,
reduction_struct *rsptr); staticvoid badusage(void);
int main(int argc, char *argv[])
{ int arg, delim, numsubgens, numsubelts, nochangect, eltct, genct, aw; char gpname[100], inf_wa[100], inf_gred[100], inf_cosred[100], suffix[100],
inf_sub[100], fsaname[100], outf[100], tempfilename[100];
boolean wordfile, diff1_ip, diff2_ip, diff1c_ip, open, rws_ipcos, diff1_ipcos,
diff2_ipcos;
gen_hash_table cosht;
gen *cosht_ptr;
gen gtestword[MAXREDUCELEN + 1], costestword[MAXREDUCELEN + 1]; int ngens, *inv; int i, l, ns;
fsa gwa, subwa, *subgwa; char **names; static gen_hash_table ght;
rewriting_system rws, *rwsptr;
reduction_struct grs, cosrs; int maxstates = MAXSTATES; int nochange = NOCHANGE;
/* First sort out the reduction automaton and routine for the group */
strcpy(inf_gred, gpname); if (diff1_ip)
strcat(inf_gred, ".diff1"); elseif (diff2_ip)
strcat(inf_gred, ".diff2"); elseif (diff1c_ip)
strcat(inf_gred, ".diff1c"); else {
diff2_ip = TRUE;
strcpy(inf_gred, gpname);
strcat(inf_gred, ".diff2");
}
if ((rfile = fopen(inf_gred, "r")) == 0) {
fprintf(stderr, "Cannot open file %s.\n", inf_gred); exit(1);
}
tmalloc(grs.wd_fsa, fsa, 1)
fsa_read(rfile, grs.wd_fsa, DENSE, 0, 0, TRUE, fsaname);
fclose(rfile);
ngens = grs.wd_fsa->alphabet->base->size;
process_names(grs.wd_fsa->alphabet->base->names, ngens);
grs.separator = ngens + 1;
cosrs.separator = ngens + 1; /* Set the pointers in the word-difference machine */ if (fsa_table_dptr_init(grs.wd_fsa) == -1) exit(1);
/* Now the word-reduction machine for cosets */ if (strncmp(suffix, "sub", 3) == 0) {
strcpy(inf_cosred, gpname);
strcat(inf_cosred, ".cos");
strcat(inf_cosred, suffix + 3);
} else {
strcpy(inf_cosred, gpname);
strcat(inf_cosred, ".");
strcat(inf_cosred, suffix);
strcat(inf_cosred, "_cos");
}
/* Set the generator names and the reduction algorithms. */
names = grs.wd_fsa->alphabet->base->names;
reduce_word = diff_reduce;
reduce_word_cos = rws_ipcos ? rws_reduce : diff_reduce_cos;
/* Now read the word-acceptor for the group */
strcpy(inf_wa, gpname);
strcat(inf_wa, ".wa"); if ((rfile = fopen(inf_wa, "r")) == 0) {
fprintf(stderr, "Cannot open file %s.\n", inf_wa); exit(1);
}
fsa_read(rfile, &gwa, DENSE, 0, 0, TRUE, fsaname);
fclose(rfile);
/* Now we initialise the subgroup word-acceptor that we shall be building */
fsa_init_subwa(&subwa, &gwa, &cosht, ngens, maxstates); /* Calculate inverses of G-generators */
tmalloc(inv, int, ngens + 1); if (calc_inv(gtestword, ngens, inv, &grs) == -1) exit(1); /* Initialise the hash table for storing the words in the G-generators that * lie in the subgroup.
*/
gen_hash_init(&ght, FALSE, 0, 0, 0);
/* Now open the file containing the words that generate the subgroup, * store them in the hash-table ght, and add them and their inverses to * the language accepted by subwa.
*/ if ((rfile = fopen(inf_sub, "r")) == 0) {
fprintf(stderr, "Cannot open file %s.\n", inf_sub); exit(1);
}
read_ident(rfile, kbm_buffer, &delim, FALSE); /* this is the name of the record containing the subgenerators */ if (delim != ':') {
fprintf(stderr, "#Input error: file must contain a record assignment\n"); exit(1);
}
check_next_char(rfile, '=');
read_ident(rfile, kbm_buffer, &delim, FALSE); if (delim != '(' || strcmp(kbm_buffer, "rec") != 0) {
fprintf(stderr, "#Input error: file must contain a record assignment\n"); exit(1);
}
read_ident(rfile, kbm_buffer, &delim, FALSE); if (strcmp(kbm_buffer, "subGenerators") != 0) {
fprintf(stderr, "Input error. 'subGenerators' list expected in subgroup " "generator file.\n"); exit(1);
} if (delim != ':') {
fprintf(stderr, "#Input error: bad 'subgens' list assignment\n"); exit(1);
}
check_next_char(rfile, '=');
check_next_char(rfile, '[');
numsubgens = 0;
numsubelts = 0; do { if (!read_word(rfile, gtestword, gtestword + rws.maxreducelen, &delim,
names, ngens, TRUE)) {
fprintf(stderr, "#Input error: no subgroup generators or missing word.\n"); exit(1);
} /* Check that it is reduced as a word in G */ if ((*reduce_word)(gtestword, &grs) == -1) exit(1); if (genstrlen(gtestword) > 0) { /* Copy it into the hash-table and see if it is new */
genstrcpy(ght.current_ptr, gtestword); if (gen_hash_locate(&ght, genstrlen(gtestword) + 1) > numsubgens) { /*It is new - so add it to language of subwa */
numsubgens++; if (add_word_fsa(&subwa, ngens, maxstates, gtestword, costestword,
names, &cosht, &cosrs) == -1) exit(1); /* Now try its inverse */
invert_word(gtestword, inv); if ((*reduce_word)(gtestword, &grs) == -1) exit(1);
genstrcpy(ght.current_ptr, gtestword); if (gen_hash_locate(&ght, genstrlen(gtestword) + 1) > numsubgens) { /*It is new - so add it to language of subwa */
numsubgens++; if (add_word_fsa(&subwa, ngens, maxstates, gtestword, costestword,
names, &cosht, &cosrs) == -1) exit(1);
}
}
}
} while (delim != ']');
fclose(rfile);
if (numsubgens * numsubgens > nochange) {
nochange = numsubgens * numsubgens <= MAXNOCHANGE ? numsubgens * numsubgens
: MAXNOCHANGE; if (kbm_print_level > 1)
printf(" #Due to large number of subgp. gens., increasing nochange to " "%d.\n",
nochange);
} if (kbm_print_level > 0)
printf("#There are %d subgroup generators (including inverses).\n",
numsubgens);
/* Now we start to go through the sugroup elements stored in ght, and * multiply them by the subgroup generators to get new words in the * subgroup, and add them to the language of subwa. * We stop after considering nochange words in the subgroup generators * with no change to subwa.
*/
numsubelts = numsubgens;
nochangect = 0; for (eltct = 1; eltct <= numsubelts && nochangect < nochange; eltct++) for (genct = 1; genct <= numsubgens && nochangect < nochange; genct++) {
genstrcpy(gtestword, gen_hash_rec(&ght, eltct));
genstrcat(gtestword, gen_hash_rec(&ght, genct)); /* Reduce it as a word in G */ if ((*reduce_word)(gtestword, &grs) == -1) exit(1); if (genstrlen(gtestword) > 0) { /* Copy it into the hash-table and see if it is new */
genstrcpy(ght.current_ptr, gtestword); if (gen_hash_locate(&ght, genstrlen(gtestword) + 1) > numsubelts) { /*It is new - so add it to language of subwa */
numsubelts++; if (kbm_print_level > 1 &&
((numsubelts <= 500 && numsubelts % 100 == 0) ||
numsubelts % 500 == 0))
printf(" #Number of subgroup elements stored=%d.\n", numsubelts);
aw = add_word_fsa(&subwa, ngens, maxstates, gtestword, costestword,
names, &cosht, &cosrs); if (aw == -1) exit(1); if (aw == 1)
nochangect = 0; else
nochangect++; /* Now try its inverse */
invert_word(gtestword, inv); if ((*reduce_word)(gtestword, &grs) == -1) exit(1);
genstrcpy(ght.current_ptr, gtestword); if (gen_hash_locate(&ght, genstrlen(gtestword) + 1) > numsubgens) { /*It is new - so add it to language of subwa */
numsubelts++; if (kbm_print_level > 1 &&
((numsubelts <= 500 && numsubelts % 100 == 0) ||
numsubelts % 500 == 0))
printf(" #Number of subgroup elements stored=%d.\n", numsubelts);
aw = add_word_fsa(&subwa, ngens, maxstates, gtestword, costestword,
names, &cosht, &cosrs); if (aw == -1) exit(1); if (aw == 1)
nochangect = 0; else
nochangect++;
}
}
}
}
/* record the coset reps. as labels of the states */
ns = subwa.states->size;
subwa.states->type = LABELED;
tmalloc(subwa.states->labels, srec, 1);
subwa.states->labels->size = ns;
subwa.states->labels->type = WORDS;
subwa.states->labels->alphabet_size = ngens; for (i = 1; i <= ngens; i++) {
l = stringlen(grs.wd_fsa->alphabet->base->names[i]);
tmalloc(subwa.states->labels->alphabet[i], char, l + 1);
strcpy(subwa.states->labels->alphabet[i],
grs.wd_fsa->alphabet->base->names[i]);
}
tmalloc(subwa.states->setToLabels, setToLabelsType, ns + 1);
tmalloc(subwa.states->labels->words, gen *, ns + 1);
subwa.states->setToLabels[0] = 0; for (i = 1; i <= ns; i++) {
cosht_ptr = gen_hash_rec(&cosht, i);
l = gen_hash_rec_len(&cosht, i);
tmalloc(subwa.states->labels->words[i], gen, l + 1);
genstrcpy(subwa.states->labels->words[i], cosht_ptr);
subwa.states->setToLabels[i] = i;
} if (kbm_print_level > 1) {
printf(" #Initial subgroup word-acceptor with %d states computed.\n", ns);
printf(" #Now and-ing it with group word-acceptor.\n");
} /* Now we "and" the subwa fsa with gwa and minimize */
subgwa = fsa_laband(&subwa, &gwa, DENSE, TRUE, tempfilename); if (kbm_print_level > 1)
printf(" #Subgroup word-acceptor with %d states before minimization " "computed.\n",
subgwa->states->size); if (fsa_labeled_minimize(subgwa) == -1) exit(1);
base_prefix(fsaname);
strcat(fsaname, ".wa");
wfile = fopen(outf, "w");
fsa_print(wfile, subgwa, fsaname);
fclose(wfile); if (kbm_print_level > 0)
printf("#Subgroup word-acceptor with %d states computed.\n",
subgwa->states->size);
/* Initialise the subgroup word-acceptor */ void fsa_init_subwa(fsa *subwaptr, fsa *gwaptr, gen_hash_table *coshtptr, int ngens, int maxstates)
{ int i;
fsa_init(subwaptr);
subwaptr->states->size = 1;
srec_copy(subwaptr->alphabet, gwaptr->alphabet);
subwaptr->num_initial = 1;
tmalloc(subwaptr->initial, int, 2);
subwaptr->initial[1] = 1; /* The initial state is also the single accepting state */
subwaptr->num_accepting = 1;
tmalloc(subwaptr->accepting, int, 2);
subwaptr->accepting[1] = 1;
fsa_table_init(subwaptr->table, maxstates, ngens);
subwaptr->table->printing_format = DENSE; for (i = 1; i <= ngens; i++)
set_dense_target(subwaptr->table->table_data_ptr, i, 1, 0);
/* The states of subwa will be cosets of the subgroup in G. * They will be stored as G-words, specifying the minimal coset rep. * These words will be stored in the hash-table *coshtptr. * We initialise the word for the first state as the empty word.
*/
gen_hash_init(coshtptr, FALSE, 0, 0, 0);
coshtptr->current_ptr[0] = '\0'; if (gen_hash_locate(coshtptr, 1) != 1) {
fprintf(stderr, "Hash-initialisation problem in fsa_init_subwa.\n"); exit(1);
}
}
/* Calculates inverses of generators - essentially the same as the routine * calculate_inverses in ../lib/worddiff.c, but it is not convenient to * use that here.
*/ int calc_inv(gen *gtestword, int ngens, int *inv, reduction_struct *rsptr)
{ int i, j; for (i = 1; i <= ngens; i++) for (j = 1; j <= ngens; j++) {
gtestword[0] = i;
gtestword[1] = j;
gtestword[2] = '\0'; if ((*reduce_word)(gtestword, rsptr) == -1) return -1; if (genstrlen(gtestword) == 0) {
inv[i] = j; break;
}
} return 0;
}
/* Invert the word in gtestword */ void invert_word(gen *gtestword, int *inv)
{
gen *wb, *we, swap;
wb = gtestword;
we = gtestword + genstrlen(gtestword) - 1; while (wb < we) {
swap = inv[*wb];
*wb = inv[*we];
*we = swap;
wb++;
we--;
} if (wb == we)
*wb = inv[*wb];
}
/* Alter the fsa subwa to make it accept the word gtestword */ int add_word_fsa(fsa *subwaptr, int ngens, int maxstates, gen *gtestword,
gen *costestword, char **names, gen_hash_table *coshtptr,
reduction_struct *rsptr)
{ int state, i, j, glen, coslen, newstate, imstate;
gen *cosrep, g; int changed = 0; int **subwa_table = subwaptr->table->table_data_ptr;
kbm_buffer[0] = '\0';
add_word_to_buffer(stdout, gtestword, names); /* In case there is an error and we need to print gtestword */
state = 1;
costestword[0] = rsptr->separator;
costestword[1] = '\0'; /* We reduce the word _H*gtestword symbol by symbol, tracing it through * subwa as we go.
*/
glen = genstrlen(gtestword); for (i = 0; i < glen; i++) {
coslen = genstrlen(costestword);
g = gtestword[i];
costestword[coslen] = g;
costestword[coslen + 1] = '\0'; if ((*reduce_word_cos)(costestword, rsptr) == -1) return -1;
cosrep = costestword; while (*cosrep != rsptr->separator)
cosrep++;
cosrep++; /* Copy the coset-rep into the hash-table, and see if we have it already */
genstrcpy(coshtptr->current_ptr, cosrep);
newstate = gen_hash_locate(coshtptr, genstrlen(cosrep) + 1); if (newstate > subwaptr->states->size) { /* New state! */
changed = 1; if (newstate > maxstates) {
fprintf(stderr, "Too many states in subwa - increase maxstates.\n"); exit(1);
} if (kbm_print_level > 1 &&
((newstate <= 500 && newstate % 100 == 0) || newstate % 500 == 0))
printf(" #Number of states in subwa = %d.\n", newstate); for (j = 1; j <= ngens; j++)
set_dense_target(subwa_table, j, newstate, 0);
subwaptr->states->size = newstate; /* should be subwaptr->states->size+1 ! */
} if ((imstate = dense_target(subwa_table, g, state)) &&
imstate != newstate) {
fprintf(stderr, "Error tracing word: ");
printbuffer(stdout); exit(1);
}
set_dense_target(subwa_table, g, state, newstate);
state = newstate;
} if (state != 1) {
fprintf(stderr, "Final error tracing word: ");
printbuffer(stdout); exit(1);
} return changed;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.