1 /* file fsarevmid.c 18. 4. 96.
2 *
3 * 16.7.98. added fsa_miexists1, fsa_miexists2 to existentialise over
4 * the two variables of a 2-variable midfa machine.
5 *
6 * 11.9.97. wrote a different version of fsa_reverse
7 * called fsa_mireverse which * returns a labeled MIDFA with the
8 * singleton accept states of the input fsa as initial states.
9 *
10 * This file contains the routine fsa_reverse.
11 * It takes a determinstic fsa F as input.
12 * fsa_reverse returns an fsa that accepts a word a_1a_2...a_n if and only
13 * if F accepts a_n...a_2a_1.
14 */
15
16 #include <stdio.h>
17 #include "defs.h"
18 #include "fsa.h"
19 #include "hash.h"
20 #include "externals.h"
21
22
23 /* Functions defined in this file: */
24 static fsa *fsa_reverse_short(fsa *fsaptr, storage_type op_table_type,
25 boolean destroy, boolean subsets,
26 char *tempfilename);
27 static fsa *fsa_reverse_int(fsa *fsaptr, storage_type op_table_type,
28 boolean destroy, boolean subsets,
29 char *tempfilename);
30 static fsa *fsa_mireverse_short(fsa *fsaptr, storage_type op_table_type,
31 boolean destroy, char *tempfilename);
32 static fsa *fsa_mireverse_int(fsa *fsaptr, storage_type op_table_type,
33 boolean destroy, char *tempfilename);
34 static fsa *fsa_miexists1_short(fsa *fsaptr, storage_type op_table_type,
35 boolean destroy, char *tempfilename);
36 static fsa *fsa_miexists1_int(fsa *fsaptr, storage_type op_table_type,
37 boolean destroy, char *tempfilename);
38 static fsa *fsa_miexists2_short(fsa *fsaptr, storage_type op_table_type,
39 boolean destroy, char *tempfilename);
40 static fsa *fsa_miexists2_int(fsa *fsaptr, storage_type op_table_type,
41 boolean destroy, char *tempfilename);
42
43
44 /* *fsaptr must be a deterministic fsa.
45 * The returned *fsa accepts words accepted by *fsaptr but read
46 * backwards.
47 * If subsets is true, then the returned fsa will have state-set of type
48 * "list of integers", where the list represents the subset of the state-set
49 * of *fsaptr that correponds to the state of the returned fsa.
50 */
fsa_reverse(fsa * fsaptr,storage_type op_table_type,boolean destroy,boolean subsets,char * tempfilename)51 fsa *fsa_reverse(fsa *fsaptr, storage_type op_table_type, boolean destroy,
52 boolean subsets, char *tempfilename)
53 {
54 if (kbm_print_level >= 3)
55 printf(" #Calling fsa_reverse.\n");
56 if (fsaptr->states->size < MAXUSHORT)
57 return fsa_reverse_short(fsaptr, op_table_type, destroy, subsets,
58 tempfilename);
59 else
60 return fsa_reverse_int(fsaptr, op_table_type, destroy, subsets,
61 tempfilename);
62 }
63
fsa_reverse_short(fsa * fsaptr,storage_type op_table_type,boolean destroy,boolean subsets,char * tempfilename)64 static fsa *fsa_reverse_short(fsa *fsaptr, storage_type op_table_type,
65 boolean destroy, boolean subsets,
66 char *tempfilename)
67 {
68 int **table, ne, nsi, ns, is, dr, *fsarow, nt, cstate, cs, csi, im, i, g, n,
69 len = 0, ct;
70 unsigned short *ht_ptr, *ht_chptr, *ht_ptrb, *ht_ptre, *cs_ptr, *cs_ptre,
71 *ptr;
72 boolean dense_ip, dense_op;
73 short_hash_table ht;
74 fsa *reverse;
75 FILE *tempfile;
76
77 if (kbm_print_level >= 3)
78 printf(" #Calling fsa_reverse_short.\n");
79 if (!fsaptr->flags[DFA]) {
80 fprintf(stderr, "Error: fsa_reverse only applies to DFA's.\n");
81 return 0;
82 }
83
84 tmalloc(reverse, fsa, 1);
85 fsa_init(reverse);
86 srec_copy(reverse->alphabet, fsaptr->alphabet);
87 reverse->flags[DFA] = TRUE;
88 reverse->flags[ACCESSIBLE] = TRUE;
89 reverse->flags[BFS] = TRUE;
90
91 reverse->states->type = subsets ? LISTOFINTS : SIMPLE;
92
93 reverse->table->table_type = op_table_type;
94 reverse->table->denserows = 0;
95 reverse->table->printing_format = op_table_type;
96
97 if (fsaptr->num_initial == 0 || fsaptr->num_accepting == 0) {
98 reverse->num_initial = 0;
99 reverse->num_accepting = 0;
100 reverse->states->size = 0;
101 if (destroy)
102 fsa_clear(fsaptr);
103 return reverse;
104 }
105 ne = fsaptr->alphabet->size;
106 nsi = fsaptr->states->size;
107
108 dense_ip = fsaptr->table->table_type == DENSE;
109 dr = fsaptr->table->denserows;
110 dense_op = op_table_type == DENSE;
111 table = fsaptr->table->table_data_ptr;
112
113 reverse->num_initial = 1;
114 tmalloc(reverse->initial, int, 2);
115 reverse->initial[1] = 1;
116
117 /* The states of *reverse will be subsets of the state-set of *fsaptr.
118 * The initial state consists of all accept states of *fsaptr.
119 */
120 short_hash_init(&ht, FALSE, 0, 0, 0);
121 ht_ptrb = ht.current_ptr;
122 ht_ptre = ht_ptrb - 1;
123 fsa_set_is_accepting(fsaptr);
124 for (i = 1; i <= nsi; i++)
125 if (fsaptr->is_accepting[i])
126 *(++ht_ptre) = i;
127 tfree(fsaptr->is_accepting);
128 im = short_hash_locate(&ht, ht_ptre - ht_ptrb + 1);
129 if (im != 1) {
130 fprintf(stderr, "Hash-initialisation problem in fsa_reverse.\n");
131 return 0;
132 }
133 if ((tempfile = fopen(tempfilename, "w")) == 0) {
134 fprintf(stderr, "Error: cannot open file %s\n", tempfilename);
135 return 0;
136 }
137 if (dense_op)
138 tmalloc(fsarow, int, ne) else tmalloc(fsarow, int, 2 * ne + 1)
139
140 cstate = 0;
141 if (dense_op)
142 len = ne; /* The length of the fsarow output. */
143 nt = 0; /* Number of transitions in reverse */
144
145 while (++cstate <= ht.num_recs) {
146 if (kbm_print_level >= 3) {
147 if ((cstate <= 1000 && cstate % 100 == 0) ||
148 (cstate <= 10000 && cstate % 1000 == 0) ||
149 (cstate <= 100000 && cstate % 5000 == 0) || cstate % 50000 == 0)
150 printf(" #cstate = %d; number of states = %d.\n", cstate,
151 ht.num_recs);
152 }
153 cs_ptr = short_hash_rec(&ht, cstate);
154 cs_ptre = short_hash_rec(&ht, cstate) + short_hash_rec_len(&ht, cstate) - 1;
155 if (!dense_op)
156 len = 0;
157
158 for (g = 1; g <= ne; g++) {
159 /* Calculate action of label g on state cstate - to get the image, we
160 * have to look for all inverse images under g of all states cs in the
161 * subset cstate. The subset formed will be the image.
162 */
163 ht_ptrb = ht.current_ptr;
164 ht_ptre = ht_ptrb - 1;
165 ptr = cs_ptr - 1;
166 while (++ptr <= cs_ptre) {
167 cs = *ptr;
168 for (csi = 1; csi <= nsi; csi++)
169 if (target(dense_ip, table, g, csi, dr) == cs) {
170 /* csi has to be added to the subset of states that forms the image
171 * of cstate under g - we want to keep this subset in ascending
172 * order.
173 */
174 if (ht_ptrb > ht_ptre || csi > *ht_ptre) {
175 *(++ht_ptre) = csi;
176 }
177 else {
178 ht_chptr = ht_ptrb;
179 while (*ht_chptr < csi)
180 ht_chptr++;
181 if (csi < *ht_chptr) {
182 ht_ptr = ++ht_ptre;
183 while (ht_ptr > ht_chptr) {
184 *ht_ptr = *(ht_ptr - 1);
185 ht_ptr--;
186 }
187 *ht_ptr = csi;
188 }
189 }
190 }
191 }
192 im = short_hash_locate(&ht, ht_ptre - ht_ptrb + 1);
193 if (dense_op)
194 fsarow[g - 1] = im;
195 else if (im > 0) {
196 fsarow[++len] = g;
197 fsarow[++len] = im;
198 }
199 if (im > 0)
200 nt++;
201 }
202 if (!dense_op)
203 fsarow[0] = len++;
204 fwrite((void *)fsarow, sizeof(int), (size_t)len, tempfile);
205 }
206 fclose(tempfile);
207
208 ns = reverse->states->size = ht.num_recs;
209 reverse->table->numTransitions = nt;
210
211 /* Locate the accept states. These are those that contain the initial
212 * state of *fsaptr.
213 * Also, if subsets is true, record the states in the intlist field
214 * of reverse->states.
215 */
216 is = fsaptr->initial[1];
217 tmalloc(reverse->is_accepting, boolean, ns + 1);
218 for (i = 1; i <= ns; i++)
219 reverse->is_accepting[i] = FALSE;
220 if (subsets)
221 tmalloc(reverse->states->intlist, int *, ns + 1);
222 ct = 0;
223 for (cstate = 1; cstate <= ns; cstate++) {
224 len = short_hash_rec_len(&ht, cstate);
225 cs_ptr = short_hash_rec(&ht, cstate);
226 cs_ptre = cs_ptr + len - 1;
227 /* See if the set contains the initial state */
228 ptr = cs_ptr - 1;
229 while (++ptr <= cs_ptre)
230 if (*ptr == is) {
231 reverse->is_accepting[cstate] = TRUE;
232 ct++;
233 break;
234 }
235 if (subsets) {
236 tmalloc(reverse->states->intlist[cstate], int, len + 1);
237 reverse->states->intlist[cstate][0] = len;
238 n = 0;
239 ptr = cs_ptr - 1;
240 while (++ptr <= cs_ptre)
241 reverse->states->intlist[cstate][++n] = *ptr;
242 }
243 }
244
245 reverse->num_accepting = ct;
246 if (ct == 1 || ct != ns) {
247 tmalloc(reverse->accepting, int, ct + 1);
248 ct = 0;
249 for (i = 1; i <= ns; i++)
250 if (reverse->is_accepting[i])
251 reverse->accepting[++ct] = i;
252 }
253 tfree(reverse->is_accepting);
254 short_hash_clear(&ht);
255 tfree(fsarow);
256
257 if (destroy)
258 fsa_clear(fsaptr);
259
260 /* Now read the transition table back in */
261 tempfile = fopen(tempfilename, "r");
262 compressed_transitions_read(reverse, tempfile);
263 fclose(tempfile);
264
265 unlink(tempfilename);
266
267 return reverse;
268 }
269
fsa_reverse_int(fsa * fsaptr,storage_type op_table_type,boolean destroy,boolean subsets,char * tempfilename)270 fsa *fsa_reverse_int(fsa *fsaptr, storage_type op_table_type, boolean destroy,
271 boolean subsets, char *tempfilename)
272 {
273 fprintf(stderr, "Sorry - fsa_reverse is not yet implemented for machines.\n");
274 fprintf(stderr, "with more than 65536 states.\n");
275 return 0;
276 }
277
278 /* *fsaptr must be a deterministic fsa.
279 * The returned *fsa accepts words accepted by *fsaptr read backwards,
280 * and is a labeled MIDFA, with initial states the singleton accept states of
281 * *fsaptr.
282 */
fsa_mireverse(fsa * fsaptr,storage_type op_table_type,boolean destroy,char * tempfilename)283 fsa *fsa_mireverse(fsa *fsaptr, storage_type op_table_type, boolean destroy,
284 char *tempfilename)
285 {
286 if (kbm_print_level >= 3)
287 printf(" #Calling fsa_mireverse.\n");
288 if (fsaptr->states->size < MAXUSHORT)
289 return fsa_mireverse_short(fsaptr, op_table_type, destroy, tempfilename);
290 else
291 return fsa_mireverse_int(fsaptr, op_table_type, destroy, tempfilename);
292 }
293
fsa_mireverse_short(fsa * fsaptr,storage_type op_table_type,boolean destroy,char * tempfilename)294 static fsa *fsa_mireverse_short(fsa *fsaptr, storage_type op_table_type,
295 boolean destroy, char *tempfilename)
296 {
297 int **table, ne, nsi, ns, nai, is, dr, *fsarow, nt, cstate, cs, csi, im, i, g,
298 len = 0, ct;
299 unsigned short *ht_ptr, *ht_chptr, *ht_ptrb, *ht_ptre, *cs_ptr, *cs_ptre,
300 *ptr;
301 boolean dense_ip, dense_op;
302 short_hash_table ht;
303 fsa *reverse;
304 srec *labs;
305 FILE *tempfile;
306
307 if (kbm_print_level >= 3)
308 printf(" #Calling fsa_mireverse_short.\n");
309 if (!fsaptr->flags[DFA]) {
310 fprintf(stderr, "Error: fsa_mireverse only applies to DFA's.\n");
311 return 0;
312 }
313
314 tmalloc(reverse, fsa, 1);
315 fsa_init(reverse);
316 srec_copy(reverse->alphabet, fsaptr->alphabet);
317 reverse->flags[MIDFA] = TRUE;
318 reverse->flags[ACCESSIBLE] = TRUE;
319
320 ne = fsaptr->alphabet->size;
321 nsi = fsaptr->states->size;
322
323 /* set up the labels for the states of reverse */
324 reverse->states->type = LABELED;
325 tmalloc(reverse->states->labels, srec, 1);
326 labs = reverse->states->labels;
327 nai = fsaptr->num_accepting;
328 labs->size = nai + 2;
329 labs->type = LISTOFINTS;
330 /* The labels will be [i] for all initial states i of fsa,
331 * [0] for other accepting states of reverse, and [] for other states.
332 */
333 tmalloc(labs->intlist, int *, nai + 3);
334 for (i = 1; i <= nai; i++) {
335 tmalloc(labs->intlist[i], int, 2);
336 labs->intlist[i][0] = 1;
337 labs->intlist[i][1] = nsi == nai ? i : fsaptr->accepting[i];
338 }
339 tmalloc(labs->intlist[nai + 1], int, 2);
340 labs->intlist[nai + 1][0] = 1;
341 labs->intlist[nai + 1][1] = 0;
342 tmalloc(labs->intlist[nai + 2], int, 1);
343 labs->intlist[nai + 2][0] = 0;
344
345 reverse->table->table_type = op_table_type;
346 reverse->table->denserows = 0;
347 reverse->table->printing_format = op_table_type;
348
349 if (fsaptr->num_initial == 0 || fsaptr->num_accepting == 0) {
350 reverse->num_initial = 0;
351 reverse->num_accepting = 0;
352 reverse->states->size = 0;
353 if (destroy)
354 fsa_clear(fsaptr);
355 return reverse;
356 }
357
358 dense_ip = fsaptr->table->table_type == DENSE;
359 dr = fsaptr->table->denserows;
360 dense_op = op_table_type == DENSE;
361 table = fsaptr->table->table_data_ptr;
362
363 reverse->num_initial = nai;
364 tmalloc(reverse->initial, int, nai + 1);
365 for (i = 1; i <= nai; i++)
366 reverse->initial[i] = i;
367
368 /* The states of *reverse will be subsets of the state-set of *fsaptr.
369 * The initial states consists of all singleton accept states of *fsaptr.
370 */
371 short_hash_init(&ht, FALSE, 0, 0, 0);
372 for (i = 1; i <= nai; i++) {
373 ht_ptrb = ht.current_ptr;
374 *ht_ptrb = nsi == nai ? i : fsaptr->accepting[i];
375 im = short_hash_locate(&ht, 1);
376 if (im != i) {
377 fprintf(stderr, "Hash-initialisation problem in fsa_reverse.\n");
378 return 0;
379 }
380 }
381 if ((tempfile = fopen(tempfilename, "w")) == 0) {
382 fprintf(stderr, "Error: cannot open file %s\n", tempfilename);
383 return 0;
384 }
385 if (dense_op)
386 tmalloc(fsarow, int, ne) else tmalloc(fsarow, int, 2 * ne + 1)
387
388 cstate = 0;
389 if (dense_op)
390 len = ne; /* The length of the fsarow output. */
391 nt = 0; /* Number of transitions in reverse */
392
393 while (++cstate <= ht.num_recs) {
394 if (kbm_print_level >= 3) {
395 if ((cstate <= 1000 && cstate % 100 == 0) ||
396 (cstate <= 10000 && cstate % 1000 == 0) ||
397 (cstate <= 100000 && cstate % 5000 == 0) || cstate % 50000 == 0)
398 printf(" #cstate = %d; number of states = %d.\n", cstate,
399 ht.num_recs);
400 }
401 cs_ptr = short_hash_rec(&ht, cstate);
402 cs_ptre = short_hash_rec(&ht, cstate) + short_hash_rec_len(&ht, cstate) - 1;
403 if (!dense_op)
404 len = 0;
405
406 for (g = 1; g <= ne; g++) {
407 /* Calculate action of label g on state cstate - to get the image, we
408 * have to look for all inverse images under g of all states cs in the
409 * subset cstate. The subset formed will be the image.
410 */
411 ht_ptrb = ht.current_ptr;
412 ht_ptre = ht_ptrb - 1;
413 ptr = cs_ptr - 1;
414 while (++ptr <= cs_ptre) {
415 cs = *ptr;
416 for (csi = 1; csi <= nsi; csi++)
417 if (target(dense_ip, table, g, csi, dr) == cs) {
418 /* csi has to be added to the subset of states that forms the image
419 * of cstate under g - we want to keep this subset in ascending
420 * order.
421 */
422 if (ht_ptrb > ht_ptre || csi > *ht_ptre) {
423 *(++ht_ptre) = csi;
424 }
425 else {
426 ht_chptr = ht_ptrb;
427 while (*ht_chptr < csi)
428 ht_chptr++;
429 if (csi < *ht_chptr) {
430 ht_ptr = ++ht_ptre;
431 while (ht_ptr > ht_chptr) {
432 *ht_ptr = *(ht_ptr - 1);
433 ht_ptr--;
434 }
435 *ht_ptr = csi;
436 }
437 }
438 }
439 }
440 im = short_hash_locate(&ht, ht_ptre - ht_ptrb + 1);
441 if (dense_op)
442 fsarow[g - 1] = im;
443 else if (im > 0) {
444 fsarow[++len] = g;
445 fsarow[++len] = im;
446 }
447 if (im > 0)
448 nt++;
449 }
450 if (!dense_op)
451 fsarow[0] = len++;
452 fwrite((void *)fsarow, sizeof(int), (size_t)len, tempfile);
453 }
454 fclose(tempfile);
455
456 ns = reverse->states->size = ht.num_recs;
457 reverse->table->numTransitions = nt;
458
459 /* Initialize the state setToLabels ptr.
460 * Then locate the accept states. These are those that contain the initial
461 * state of *fsaptr.
462 */
463 tmalloc(reverse->states->setToLabels, setToLabelsType, ns + 1);
464 for (i = 1; i <= nai; i++)
465 reverse->states->setToLabels[i] = i;
466
467 is = fsaptr->initial[1];
468 tmalloc(reverse->is_accepting, boolean, ns + 1);
469 for (i = 1; i <= ns; i++)
470 reverse->is_accepting[i] = FALSE;
471 ct = 0;
472 for (cstate = 1; cstate <= ns; cstate++) {
473 len = short_hash_rec_len(&ht, cstate);
474 cs_ptr = short_hash_rec(&ht, cstate);
475 cs_ptre = cs_ptr + len - 1;
476 /* See if the set contains the initial state */
477 ptr = cs_ptr - 1;
478 while (++ptr <= cs_ptre)
479 if (*ptr == is) {
480 reverse->is_accepting[cstate] = TRUE;
481 ct++;
482 break;
483 }
484 if (cstate > nai)
485 reverse->states->setToLabels[cstate] =
486 reverse->is_accepting[cstate] ? nai + 1 : nai + 2;
487 }
488
489 reverse->num_accepting = ct;
490 if (ct == 1 || ct != ns) {
491 tmalloc(reverse->accepting, int, ct + 1);
492 ct = 0;
493 for (i = 1; i <= ns; i++)
494 if (reverse->is_accepting[i])
495 reverse->accepting[++ct] = i;
496 }
497 tfree(reverse->is_accepting);
498 short_hash_clear(&ht);
499 tfree(fsarow);
500
501 if (destroy)
502 fsa_clear(fsaptr);
503
504 /* Now read the transition table back in */
505 tempfile = fopen(tempfilename, "r");
506 compressed_transitions_read(reverse, tempfile);
507 fclose(tempfile);
508
509 unlink(tempfilename);
510
511 return reverse;
512 }
513
fsa_mireverse_int(fsa * fsaptr,storage_type op_table_type,boolean destroy,char * tempfilename)514 static fsa *fsa_mireverse_int(fsa *fsaptr, storage_type op_table_type,
515 boolean destroy, char *tempfilename)
516 {
517 fprintf(stderr,
518 "Sorry - fsa_mireverse is not yet implemented for machines.\n");
519 fprintf(stderr, "with more than 65536 states.\n");
520 return 0;
521 }
522
523 /* *fsaptr must be a 2-variable MIDFA fsa.
524 * The returned midfa accepts a word w_1 iff (w_1,w_2) is accepted by *fsaptr,
525 * for some word w_2 - but here the padding symbol is part of the
526 * alphabet of the output midfa.
527 * In fact, fsa_miexists1 calls fsa_miexists1_int or (more usually)
528 * fsa_miexists1_short, the latter using the short hash table functions.
529 */
fsa_miexists1(fsa * fsaptr,storage_type op_table_type,boolean destroy,char * tempfilename)530 fsa *fsa_miexists1(fsa *fsaptr, storage_type op_table_type, boolean destroy,
531 char *tempfilename)
532 {
533 if (kbm_print_level >= 3)
534 printf(" #Calling fsa_miexists1.\n");
535 if (fsaptr->states->size < MAXUSHORT)
536 return fsa_miexists1_short(fsaptr, op_table_type, destroy, tempfilename);
537 else
538 return fsa_miexists1_int(fsaptr, op_table_type, destroy, tempfilename);
539 }
540
fsa_miexists1_short(fsa * fsaptr,storage_type op_table_type,boolean destroy,char * tempfilename)541 static fsa *fsa_miexists1_short(fsa *fsaptr, storage_type op_table_type,
542 boolean destroy, char *tempfilename)
543 {
544 int **table, ne, ngens, ns, nsi, dr, *fsarow, e, es, ef, nt, cstate, cs, csi,
545 im, i, g1, len = 0, ct, ni;
546 unsigned short *ht_ptr, *ht_chptr, *ht_ptrb, *ht_ptre, *cs_ptr, *cs_ptre,
547 *ptr;
548 boolean dense_ip, dense_op;
549 short_hash_table ht;
550 fsa *miexists1;
551 FILE *tempfile;
552
553 if (kbm_print_level >= 3)
554 printf(" #Calling fsa_miexists1_short.\n");
555 if (!fsaptr->flags[MIDFA]) {
556 fprintf(stderr, "Error: fsa_miexists1 only applies to MIDFA's.\n");
557 exit(1);
558 }
559
560 if (fsaptr->alphabet->type != PRODUCT || fsaptr->alphabet->arity != 2) {
561 fprintf(stderr, "Error in fsa_miexists1: fsa must be 2-variable.\n");
562 exit(1);
563 }
564
565 tmalloc(miexists1, fsa, 1);
566 fsa_init(miexists1);
567 nsi = fsaptr->states->size;
568 ne = fsaptr->alphabet->size;
569 ngens = fsaptr->alphabet->base->size;
570
571 if (ne != (ngens + 1) * (ngens + 1) - 1) {
572 fprintf(stderr, "Error: in a 2-variable fsa, alphabet size should = "
573 "(ngens+1)^2 - 1.\n");
574 exit(1);
575 }
576 /* alphabet will include padding symbol */
577 miexists1->alphabet->type = IDENTIFIERS;
578 miexists1->alphabet->size = ngens + 1;
579 tmalloc(miexists1->alphabet->names, char *, ngens + 2);
580 for (i = 1; i <= ngens; i++) {
581 tmalloc(miexists1->alphabet->names[i], char,
582 stringlen(fsaptr->alphabet->base->names[i]) + 1);
583 strcpy(miexists1->alphabet->names[i], fsaptr->alphabet->base->names[i]);
584 }
585 tmalloc(miexists1->alphabet->names[ngens + 1], char, 2);
586 miexists1->alphabet->names[ngens + 1][0] = fsaptr->alphabet->padding;
587 miexists1->alphabet->names[ngens + 1][1] = '\0';
588 miexists1->flags[MIDFA] = TRUE;
589 miexists1->flags[ACCESSIBLE] = TRUE;
590
591 miexists1->states->type = LABELED;
592 tmalloc(miexists1->states->labels, srec, 1);
593 srec_copy(miexists1->states->labels, fsaptr->states->labels);
594
595 miexists1->table->table_type = op_table_type;
596 miexists1->table->denserows = 0;
597 miexists1->table->printing_format = op_table_type;
598
599 if (fsaptr->num_initial == 0 || fsaptr->num_accepting == 0) {
600 miexists1->num_initial = 0;
601 miexists1->num_accepting = 0;
602 miexists1->states->size = 0;
603 if (destroy)
604 fsa_clear(fsaptr);
605 return miexists1;
606 }
607
608 fsa_set_is_accepting(fsaptr);
609
610 dense_ip = fsaptr->table->table_type == DENSE;
611 dr = fsaptr->table->denserows;
612 dense_op = op_table_type == DENSE;
613 table = fsaptr->table->table_data_ptr;
614
615 ni = fsaptr->num_initial;
616 miexists1->num_initial = ni;
617 tmalloc(miexists1->initial, int, ni + 1);
618 for (i = 1; i <= ni; i++)
619 miexists1->initial[i] = i;
620
621 short_hash_init(&ht, FALSE, 0, 0, 0);
622 for (i = 1; i <= ni; i++) {
623 ht_ptrb = ht.current_ptr;
624 *ht_ptrb = nsi == ni ? i : fsaptr->initial[i];
625 im = short_hash_locate(&ht, 1);
626 if (im != i) {
627 fprintf(stderr, "Hash-initialisation problem in fsa_miexists.\n");
628 exit(1);
629 }
630 }
631 /* Each state in 'miexists1' will be represented as a subset of the states
632 * of *fsaptr. The initial states are one-element set containing the initial
633 * states of *fsaptr. A subset is an accept-state if it contains an accept
634 * state of *fsaptr.
635 * The subsets will be stored as variable-length records in the hash-table,
636 * always in increasing order.
637 */
638 if ((tempfile = fopen(tempfilename, "w")) == 0) {
639 fprintf(stderr, "Error: cannot open file %s\n", tempfilename);
640 exit(1);
641 }
642 if (dense_op)
643 tmalloc(fsarow, int, ngens) else tmalloc(fsarow, int, 2 * ngens + 1)
644
645 cstate = 0;
646 if (dense_op)
647 len = ngens + 1; /* The length of the fsarow output. */
648 nt = 0; /* Number of transitions in miexists1 */
649
650 while (++cstate <= ht.num_recs) {
651 if (kbm_print_level >= 3) {
652 if ((cstate <= 1000 && cstate % 100 == 0) ||
653 (cstate <= 10000 && cstate % 1000 == 0) ||
654 (cstate <= 100000 && cstate % 5000 == 0) || cstate % 50000 == 0)
655 printf(" #cstate = %d; number of states = %d.\n", cstate,
656 ht.num_recs);
657 }
658 cs_ptr = short_hash_rec(&ht, cstate);
659 cs_ptre = short_hash_rec(&ht, cstate) + short_hash_rec_len(&ht, cstate) - 1;
660 if (!dense_op)
661 len = 0;
662
663 for (g1 = 1; g1 <= ngens + 1; g1++) {
664 /* Calculate action of generator g1 on state cstate - to get the image,
665 * we have to apply (g1,g2) to each element in the subset corresponding to
666 * cstate, and this for each generator g2 of the base-alphabet (including
667 * the padding symbol).
668 */
669 ht_ptrb = ht.current_ptr;
670 ht_ptre = ht_ptrb - 1;
671 ptr = cs_ptr - 1;
672 es = (g1 - 1) * (ngens + 1) + 1;
673 ef = g1 == ngens + 1 ? g1 * (ngens + 1) - 1 : g1 * (ngens + 1);
674 /* As g2 ranges from 1 to ngens+1 in the pair (g1,g2), for fixed g1, the
675 * corresponding edge number in the fsa ranges from es to ef.
676 */
677 while (++ptr <= cs_ptre) {
678 cs = *ptr;
679 for (e = es; e <= ef; e++) {
680 csi = target(dense_ip, table, e, cs, dr);
681 if (csi == 0)
682 continue;
683 if (ht_ptrb > ht_ptre || csi > *ht_ptre) {
684 /* We have a new state for the image subset to be added to the end
685 */
686 *(++ht_ptre) = csi;
687 }
688 else {
689 ht_chptr = ht_ptrb;
690 while (*ht_chptr < csi)
691 ht_chptr++;
692 if (csi < *ht_chptr) {
693 /* we have a new state for the image subset to be added in the
694 * middle */
695 ht_ptr = ++ht_ptre;
696 while (ht_ptr > ht_chptr) {
697 *ht_ptr = *(ht_ptr - 1);
698 ht_ptr--;
699 }
700 *ht_ptr = csi;
701 }
702 }
703 }
704 }
705 im = short_hash_locate(&ht, ht_ptre - ht_ptrb + 1);
706 if (dense_op)
707 fsarow[g1 - 1] = im;
708 else if (im > 0) {
709 fsarow[++len] = g1;
710 fsarow[++len] = im;
711 }
712 if (im > 0)
713 nt++;
714 }
715 if (!dense_op)
716 fsarow[0] = len++;
717 fwrite((void *)fsarow, sizeof(int), (size_t)len, tempfile);
718 }
719 fclose(tempfile);
720
721 ns = miexists1->states->size = ht.num_recs;
722 miexists1->table->numTransitions = nt;
723
724 /* Locate the initial and accept states, and assign labels.
725 * A state is an accept state if the
726 * corresponding subset contains an accept state of *fsaptr.
727 * We will need to use the array miexists1->is_accepting.
728 */
729 tmalloc(miexists1->states->setToLabels, setToLabelsType, ns + 1);
730 for (i = 1; i <= ni; i++)
731 miexists1->states->setToLabels[i] =
732 fsaptr->states->setToLabels[fsaptr->initial[i]];
733 tmalloc(miexists1->is_accepting, boolean, ns + 1);
734 for (i = 1; i <= ns; i++)
735 miexists1->is_accepting[i] = FALSE;
736 ct = 0;
737 for (cstate = ns; cstate >= 1; cstate--) {
738 cs_ptr = short_hash_rec(&ht, cstate);
739 cs_ptre = short_hash_rec(&ht, cstate) + short_hash_rec_len(&ht, cstate) - 1;
740 /* See if the set an accept-state */
741 ptr = cs_ptr - 1;
742 while (++ptr <= cs_ptre)
743 if (fsaptr->is_accepting[*ptr]) {
744 miexists1->is_accepting[cstate] = TRUE;
745 ct++;
746 break;
747 }
748 if (cstate > ni)
749 miexists1->states->setToLabels[cstate] =
750 miexists1->is_accepting[cstate] ? ni + 1 : ni + 2;
751 }
752
753 miexists1->num_accepting = ct;
754 if (ct == 1 || ct != ns) {
755 tmalloc(miexists1->accepting, int, ct + 1);
756 ct = 0;
757 for (i = 1; i <= ns; i++)
758 if (miexists1->is_accepting[i])
759 miexists1->accepting[++ct] = i;
760 }
761 tfree(fsaptr->is_accepting);
762 tfree(miexists1->is_accepting);
763 short_hash_clear(&ht);
764 tfree(fsarow);
765
766 if (destroy)
767 fsa_clear(fsaptr);
768
769 /* Now read the transition table back in */
770 tempfile = fopen(tempfilename, "r");
771 compressed_transitions_read(miexists1, tempfile);
772 fclose(tempfile);
773
774 unlink(tempfilename);
775
776 return miexists1;
777 }
778
fsa_miexists1_int(fsa * fsaptr,storage_type op_table_type,boolean destroy,char * tempfilename)779 static fsa *fsa_miexists1_int(fsa *fsaptr, storage_type op_table_type,
780 boolean destroy, char *tempfilename)
781 {
782 fprintf(stderr,
783 "Sorry - fsa_miexists1 is not yet implemented for machines.\n");
784 fprintf(stderr, "with more than 65536 states.\n");
785 exit(1);
786 }
787
788 /* *fsaptr must be a 2-variable MIDFA fsa.
789 * The returned midfa accepts a word w_1 iff (w_1,w_2) is accepted by *fsaptr,
790 * for some word w_2 - but here the padding symbol is part of the
791 * alphabet of the output midfa.
792 * In fact, fsa_miexists2 calls fsa_miexists2_int or (more usually)
793 * fsa_miexists2_short, the latter using the short hash table functions.
794 */
fsa_miexists2(fsa * fsaptr,storage_type op_table_type,boolean destroy,char * tempfilename)795 fsa *fsa_miexists2(fsa *fsaptr, storage_type op_table_type, boolean destroy,
796 char *tempfilename)
797 {
798 if (kbm_print_level >= 3)
799 printf(" #Calling fsa_miexists2.\n");
800 if (fsaptr->states->size < MAXUSHORT)
801 return fsa_miexists2_short(fsaptr, op_table_type, destroy, tempfilename);
802 else
803 return fsa_miexists2_int(fsaptr, op_table_type, destroy, tempfilename);
804 }
805
fsa_miexists2_short(fsa * fsaptr,storage_type op_table_type,boolean destroy,char * tempfilename)806 static fsa *fsa_miexists2_short(fsa *fsaptr, storage_type op_table_type,
807 boolean destroy, char *tempfilename)
808 {
809 int **table, ne, ngens, ngens1, ns, nsi, dr, *fsarow, e, es, ef, nt, cstate,
810 cs, csi, im, i, g2, len = 0, ct, ni;
811 unsigned short *ht_ptr, *ht_chptr, *ht_ptrb, *ht_ptre, *cs_ptr, *cs_ptre,
812 *ptr;
813 boolean dense_ip, dense_op;
814 short_hash_table ht;
815 fsa *miexists2;
816 FILE *tempfile;
817
818 if (kbm_print_level >= 3)
819 printf(" #Calling fsa_miexists2_short.\n");
820 if (!fsaptr->flags[MIDFA]) {
821 fprintf(stderr, "Error: fsa_miexists2 only applies to MIDFA's.\n");
822 exit(1);
823 }
824
825 if (fsaptr->alphabet->type != PRODUCT || fsaptr->alphabet->arity != 2) {
826 fprintf(stderr, "Error in fsa_miexists2: fsa must be 2-variable.\n");
827 exit(1);
828 }
829
830 tmalloc(miexists2, fsa, 1);
831 fsa_init(miexists2);
832 nsi = fsaptr->states->size;
833 ne = fsaptr->alphabet->size;
834 ngens = fsaptr->alphabet->base->size;
835 ngens1 = ngens + 1;
836
837 if (ne != ngens1 * ngens1 - 1) {
838 fprintf(stderr, "Error: in a 2-variable fsa, alphabet size should = "
839 "(ngens+1)^2 - 1.\n");
840 exit(1);
841 }
842 /* alphabet will include padding symbol */
843 miexists2->alphabet->type = IDENTIFIERS;
844 miexists2->alphabet->size = ngens1;
845 tmalloc(miexists2->alphabet->names, char *, ngens + 2);
846 for (i = 1; i <= ngens; i++) {
847 tmalloc(miexists2->alphabet->names[i], char,
848 stringlen(fsaptr->alphabet->base->names[i]) + 1);
849 strcpy(miexists2->alphabet->names[i], fsaptr->alphabet->base->names[i]);
850 }
851 tmalloc(miexists2->alphabet->names[ngens1], char, 2);
852 miexists2->alphabet->names[ngens1][0] = fsaptr->alphabet->padding;
853 miexists2->alphabet->names[ngens1][1] = '\0';
854 miexists2->flags[MIDFA] = TRUE;
855 miexists2->flags[ACCESSIBLE] = TRUE;
856
857 miexists2->states->type = LABELED;
858 tmalloc(miexists2->states->labels, srec, 1);
859 srec_copy(miexists2->states->labels, fsaptr->states->labels);
860
861 miexists2->table->table_type = op_table_type;
862 miexists2->table->denserows = 0;
863 miexists2->table->printing_format = op_table_type;
864
865 if (fsaptr->num_initial == 0 || fsaptr->num_accepting == 0) {
866 miexists2->num_initial = 0;
867 miexists2->num_accepting = 0;
868 miexists2->states->size = 0;
869 if (destroy)
870 fsa_clear(fsaptr);
871 return miexists2;
872 }
873
874 fsa_set_is_accepting(fsaptr);
875
876 dense_ip = fsaptr->table->table_type == DENSE;
877 dr = fsaptr->table->denserows;
878 dense_op = op_table_type == DENSE;
879 table = fsaptr->table->table_data_ptr;
880
881 ni = fsaptr->num_initial;
882 miexists2->num_initial = ni;
883 tmalloc(miexists2->initial, int, ni + 1);
884 for (i = 1; i <= ni; i++)
885 miexists2->initial[i] = i;
886
887 short_hash_init(&ht, FALSE, 0, 0, 0);
888 for (i = 1; i <= ni; i++) {
889 ht_ptrb = ht.current_ptr;
890 *ht_ptrb = nsi == ni ? i : fsaptr->initial[i];
891 im = short_hash_locate(&ht, 1);
892 if (im != i) {
893 fprintf(stderr, "Hash-initialisation problem in fsa_miexists.\n");
894 exit(1);
895 }
896 }
897 /* Each state in 'miexists2' will be represented as a subset of the states
898 * of *fsaptr. The initial states are one-element set containing the initial
899 * states of *fsaptr. A subset is an accept-state if it contains an accept
900 * state of *fsaptr.
901 * The subsets will be stored as variable-length records in the hash-table,
902 * always in increasing order.
903 */
904 if ((tempfile = fopen(tempfilename, "w")) == 0) {
905 fprintf(stderr, "Error: cannot open file %s\n", tempfilename);
906 exit(1);
907 }
908 if (dense_op)
909 tmalloc(fsarow, int, ngens) else tmalloc(fsarow, int, 2 * ngens1)
910
911 cstate = 0;
912 if (dense_op)
913 len = ngens1; /* The length of the fsarow output. */
914 nt = 0; /* Number of transitions in miexists2 */
915
916 while (++cstate <= ht.num_recs) {
917 if (kbm_print_level >= 3) {
918 if ((cstate <= 1000 && cstate % 100 == 0) ||
919 (cstate <= 10000 && cstate % 1000 == 0) ||
920 (cstate <= 100000 && cstate % 5000 == 0) || cstate % 50000 == 0)
921 printf(" #cstate = %d; number of states = %d.\n", cstate,
922 ht.num_recs);
923 }
924 cs_ptr = short_hash_rec(&ht, cstate);
925 cs_ptre = short_hash_rec(&ht, cstate) + short_hash_rec_len(&ht, cstate) - 1;
926 if (!dense_op)
927 len = 0;
928
929 for (g2 = 1; g2 <= ngens1; g2++) {
930 /* Calculate action of generator g2 on state cstate - to get the image,
931 * we have to apply (g1,g2) to each element in the subset corresponding to
932 * cstate, and this for each generator g1 of the base-alphabet (including
933 * the padding symbol).
934 */
935 ht_ptrb = ht.current_ptr;
936 ht_ptre = ht_ptrb - 1;
937 ptr = cs_ptr - 1;
938 es = g2;
939 ef = g2 == ngens1 ? ngens * ngens + g2 : ngens * ngens1 + g2;
940 /* As g2 ranges from 1 to ngens+1 in the pair (g2,g2), for fixed g2, the
941 * corresponding edge number in the fsa ranges from es to ef.
942 */
943 while (++ptr <= cs_ptre) {
944 cs = *ptr;
945 for (e = es; e <= ef; e += ngens1) {
946 csi = target(dense_ip, table, e, cs, dr);
947 if (csi == 0)
948 continue;
949 if (ht_ptrb > ht_ptre || csi > *ht_ptre) {
950 /* We have a new state for the image subset to be added to the end
951 */
952 *(++ht_ptre) = csi;
953 }
954 else {
955 ht_chptr = ht_ptrb;
956 while (*ht_chptr < csi)
957 ht_chptr++;
958 if (csi < *ht_chptr) {
959 /* we have a new state for the image subset to be added in the
960 * middle */
961 ht_ptr = ++ht_ptre;
962 while (ht_ptr > ht_chptr) {
963 *ht_ptr = *(ht_ptr - 1);
964 ht_ptr--;
965 }
966 *ht_ptr = csi;
967 }
968 }
969 }
970 }
971 im = short_hash_locate(&ht, ht_ptre - ht_ptrb + 1);
972 if (dense_op)
973 fsarow[g2 - 1] = im;
974 else if (im > 0) {
975 fsarow[++len] = g2;
976 fsarow[++len] = im;
977 }
978 if (im > 0)
979 nt++;
980 }
981 if (!dense_op)
982 fsarow[0] = len++;
983 fwrite((void *)fsarow, sizeof(int), (size_t)len, tempfile);
984 }
985 fclose(tempfile);
986
987 ns = miexists2->states->size = ht.num_recs;
988 miexists2->table->numTransitions = nt;
989
990 /* Locate the initial and accept states, and assign labels.
991 * A state is an accept state if the
992 * corresponding subset contains an accept state of *fsaptr.
993 * We will need to use the array miexists2->is_accepting.
994 */
995 tmalloc(miexists2->states->setToLabels, setToLabelsType, ns + 1);
996 for (i = 1; i <= ni; i++)
997 miexists2->states->setToLabels[i] =
998 fsaptr->states->setToLabels[fsaptr->initial[i]];
999 tmalloc(miexists2->is_accepting, boolean, ns + 1);
1000 for (i = 1; i <= ns; i++)
1001 miexists2->is_accepting[i] = FALSE;
1002 ct = 0;
1003 for (cstate = ns; cstate >= 1; cstate--) {
1004 cs_ptr = short_hash_rec(&ht, cstate);
1005 cs_ptre = short_hash_rec(&ht, cstate) + short_hash_rec_len(&ht, cstate) - 1;
1006 /* See if the set an accept-state */
1007 ptr = cs_ptr - 1;
1008 while (++ptr <= cs_ptre)
1009 if (fsaptr->is_accepting[*ptr]) {
1010 miexists2->is_accepting[cstate] = TRUE;
1011 ct++;
1012 break;
1013 }
1014 if (cstate > ni)
1015 miexists2->states->setToLabels[cstate] =
1016 miexists2->is_accepting[cstate] ? ni + 1 : ni + 2;
1017 }
1018
1019 miexists2->num_accepting = ct;
1020 if (ct == 1 || ct != ns) {
1021 tmalloc(miexists2->accepting, int, ct + 1);
1022 ct = 0;
1023 for (i = 1; i <= ns; i++)
1024 if (miexists2->is_accepting[i])
1025 miexists2->accepting[++ct] = i;
1026 }
1027 tfree(fsaptr->is_accepting);
1028 tfree(miexists2->is_accepting);
1029 short_hash_clear(&ht);
1030 tfree(fsarow);
1031
1032 if (destroy)
1033 fsa_clear(fsaptr);
1034
1035 /* Now read the transition table back in */
1036 tempfile = fopen(tempfilename, "r");
1037 compressed_transitions_read(miexists2, tempfile);
1038 fclose(tempfile);
1039
1040 unlink(tempfilename);
1041
1042 return miexists2;
1043 }
1044
fsa_miexists2_int(fsa * fsaptr,storage_type op_table_type,boolean destroy,char * tempfilename)1045 static fsa *fsa_miexists2_int(fsa *fsaptr, storage_type op_table_type,
1046 boolean destroy, char *tempfilename)
1047 {
1048 fprintf(stderr,
1049 "Sorry - fsa_miexists2 is not yet implemented for machines.\n");
1050 fprintf(stderr, "with more than 65536 states.\n");
1051 exit(1);
1052 }
1053