1 /* file fsa.c - 16. 9. 94.
2 *
3 * 2/3/99 Bug fix in labeled_minimize();
4 * Must have at least two iterations of main loop.
5 *
6 * 9/1/98 change generators from type char to type `gen'.
7 * 2/10/97 - made minor changes necessary to handle compact table format.
8 * most functions will not handle this yet however.
9 * 27.6.96. - added functions for computing growth function of an fsa
10 * written by Laurent Bartholdi
11 * 1.5.96. - adjusted srec_copy and srec_clear to deal with
12 * srec type "list of Integers".
13 * 15.4.96. - added routing fsa_swap_coords().
14 *
15 * This file contains routines for manipulating finite state automata
16 * The functions in this file currently only deal with deterministic fsa's
17 *
18 * 13.9.95. - wrote in code to handle srec type "list of words"
19 * 17.11.94. - implemented labeled srec type and function fsa_labeled_minimize.
20 */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <assert.h>
25 #include "defs.h"
26 #include "fsa.h"
27 #include "hash.h"
28 #include "externals.h"
29
30 /* New functions written by Laurent Bartholdi for calculation of
31 * growth rate of an fsa
32 */
33 // unsigned *fsa_mod_count(); /* count # of accepted words mod. a prime */
34 // unsigned mod_inverse();
35 // int mod_solve();
36 // int fsa_mod_growth(); /* compute growth series mod. a prime */
37 // void mod_normal();
38 // boolean print_poly();
39 // int fsa_growth();
40 typedef struct {
41 int nd, *num, dd, *den;
42 } fraction;
43
44 /* p1 points to the beginning of the row of targets from the required state
45 * in a sparsely stored fsa, and p2 to the location beyond the end.
46 * g is the generator number for which we seek the target.
47 * If we don't find one, then there isn't one, and we return 0.
48 * This only works for dfa's.
49 */
sparse_target(int g,int * p1,int * p2)50 int sparse_target(int g, int *p1, int *p2)
51 {
52 while (p1 < p2) {
53 if (*p1 == g)
54 return *(p1 + 1);
55 p1 += 2;
56 }
57 return 0;
58 }
59
60 /* Allocate space for the sub-structures of fsaptr, and zero all pointers. */
fsa_init(fsa * fsaptr)61 void fsa_init(fsa *fsaptr)
62 {
63 int i;
64 fsaptr->initial = 0;
65 fsaptr->accepting = 0;
66 fsaptr->is_accepting = 0;
67 fsaptr->is_initial = 0;
68 fsaptr->is_accessible = 0;
69
70 tmalloc(fsaptr->alphabet, srec, 1);
71 fsaptr->alphabet->names = 0;
72 fsaptr->alphabet->words = 0;
73 fsaptr->alphabet->wordslist = 0;
74 fsaptr->alphabet->intlist = 0;
75 fsaptr->alphabet->base = 0;
76 fsaptr->alphabet->type = SIMPLE;
77 fsaptr->alphabet->size = 0;
78 fsaptr->alphabet->labels = 0;
79 fsaptr->alphabet->setToLabels = 0;
80
81 tmalloc(fsaptr->states, srec, 1);
82 fsaptr->states->names = 0;
83 fsaptr->states->words = 0;
84 fsaptr->states->wordslist = 0;
85 fsaptr->states->intlist = 0;
86 fsaptr->states->base = 0;
87 fsaptr->states->type = SIMPLE;
88 fsaptr->states->size = 0;
89 fsaptr->states->labels = 0;
90 fsaptr->states->setToLabels = 0;
91
92 for (i = 0; i < num_kbm_flag_strings; i++)
93 fsaptr->flags[i] = FALSE;
94 tmalloc(fsaptr->table, table_struc, 1);
95 fsaptr->table->filename = 0;
96 fsaptr->table->table_data_ptr = 0;
97 fsaptr->table->ctable_data_ptr = 0;
98 fsaptr->table->table_data_dptr = 0;
99 fsaptr->table->comment_state_numbers = FALSE;
100 }
101
102 /* Intialize the table_data_ptr field of fsaptr->table,
103 * for maxstates states, with table-type dense.
104 * ne is the size of the alphabet.
105 */
fsa_table_init(table_struc * tableptr,int maxstates,int ne)106 void fsa_table_init(table_struc *tableptr, int maxstates, int ne)
107 {
108 int i;
109 tableptr->maxstates = maxstates;
110 tableptr->table_type = DENSE;
111 tmalloc(tableptr->table_data_ptr, int *, ne + 1);
112 tmalloc(tableptr->table_data_ptr[0], int, maxstates *ne);
113 for (i = 1; i <= ne; i++)
114 tableptr->table_data_ptr[i] =
115 tableptr->table_data_ptr[0] + (i - 1) * maxstates - 1;
116 }
117
118 /* Set the is_initial field in fsa *fsaptr - should be freed after use */
fsa_set_is_initial(fsa * fsaptr)119 void fsa_set_is_initial(fsa *fsaptr)
120 {
121 int ns, i;
122 ns = fsaptr->states->size;
123 tmalloc(fsaptr->is_initial, boolean, ns + 1);
124 fsaptr->is_initial[0] = FALSE;
125 if (fsaptr->num_initial == ns) {
126 for (i = 1; i <= ns; i++)
127 fsaptr->is_initial[i] = TRUE;
128 }
129 else {
130 for (i = 1; i <= ns; i++)
131 fsaptr->is_initial[i] = FALSE;
132 for (i = 1; i <= fsaptr->num_initial; i++)
133 fsaptr->is_initial[fsaptr->initial[i]] = TRUE;
134 }
135 }
136
137 /* Set the is_accepting field in fsa *fsaptr - should be freed after use */
fsa_set_is_accepting(fsa * fsaptr)138 void fsa_set_is_accepting(fsa *fsaptr)
139 {
140 int ns, i;
141 ns = fsaptr->states->size;
142 tmalloc(fsaptr->is_accepting, boolean, ns + 1);
143 fsaptr->is_accepting[0] = FALSE;
144 if (fsaptr->num_accepting == ns) {
145 for (i = 1; i <= ns; i++)
146 fsaptr->is_accepting[i] = TRUE;
147 }
148 else {
149 for (i = 1; i <= ns; i++)
150 fsaptr->is_accepting[i] = FALSE;
151 for (i = 1; i <= fsaptr->num_accepting; i++)
152 fsaptr->is_accepting[fsaptr->accepting[i]] = TRUE;
153 }
154 }
155
156 /* Set the is_accessible field in fsa *fsaptr - should be freed after use */
fsa_set_is_accessible(fsa * fsaptr)157 void fsa_set_is_accessible(fsa *fsaptr)
158 {
159 int ns, ne, ct, i, *gotlist, **table, j, k, l, *ptr, *ptre;
160 ;
161
162 ns = fsaptr->states->size;
163 ne = fsaptr->alphabet->size;
164
165 tmalloc(gotlist, int, ns + 1);
166 tmalloc(fsaptr->is_accessible, boolean, ns + 1);
167 table = fsaptr->table->table_data_ptr;
168 ct = 0;
169 if (fsaptr->num_initial == ns) {
170 for (i = 1; i <= ns; i++)
171 fsaptr->is_accessible[i] = TRUE;
172 return;
173 }
174 for (i = 1; i <= ns; i++)
175 fsaptr->is_accessible[i] = FALSE;
176 for (i = 1; i <= fsaptr->num_initial; i++) {
177 fsaptr->is_accessible[fsaptr->initial[i]] = TRUE;
178 gotlist[++ct] = fsaptr->initial[i];
179 }
180 for (i = 1; i <= ct; i++) {
181 k = gotlist[i];
182 if (fsaptr->table->table_type == DENSE)
183 for (j = 1; j <= ne; j++) {
184 l = table[j][k];
185 if (l > 0 && !fsaptr->is_accessible[l]) {
186 fsaptr->is_accessible[l] = TRUE;
187 gotlist[++ct] = l;
188 }
189 }
190 else {
191 ptr = table[k];
192 ptre = table[k + 1];
193 while (ptr < ptre) {
194 l = *(++ptr);
195 if (l > 0 && !fsaptr->is_accessible[l]) {
196 fsaptr->is_accessible[l] = TRUE;
197 gotlist[++ct] = l;
198 }
199 ptr++;
200 }
201 }
202 }
203 tfree(gotlist);
204 }
205
206 /* Set the field fsaptr->table->table_data_dptr.
207 * This is used for fast access to table entries in 2-variable machines.
208 */
fsa_table_dptr_init(fsa * fsaptr)209 int fsa_table_dptr_init(fsa *fsaptr)
210 {
211 int i, ngens;
212 if (fsaptr->alphabet->type != PRODUCT || fsaptr->alphabet->arity != 2) {
213 fprintf(stderr, "Error in fsa_table_dptr_init: fsa must be 2-variable.\n");
214 return -1;
215 }
216 if (fsaptr->table->table_type != DENSE) {
217 fprintf(stderr,
218 "Error in fsa_table_dptr_init: storage-type must be dense.\n");
219 return -1;
220 }
221 ngens = fsaptr->alphabet->base->size;
222 if (fsaptr->table->table_data_dptr == 0) {
223 tmalloc(fsaptr->table->table_data_dptr, int **, ngens + 2);
224 for (i = 1; i <= ngens + 1; i++)
225 fsaptr->table->table_data_dptr[i] =
226 fsaptr->table->table_data_ptr + (i - 1) * (ngens + 1);
227 }
228 return 0;
229 }
230
231 /* Deallocate all space used by the set-record fsaptr */
srec_clear(srec * srptr)232 void srec_clear(srec *srptr)
233 {
234 int i, j;
235 if (srptr == 0)
236 return;
237 if ((srptr->type == IDENTIFIERS || srptr->type == STRINGS) && srptr->names) {
238 for (i = 1; i <= srptr->size; i++)
239 tfree(srptr->names[i]);
240 tfree(srptr->names);
241 }
242 if (srptr->type == WORDS && srptr->words) {
243 for (i = 1; i <= srptr->size; i++)
244 tfree(srptr->words[i]);
245 tfree(srptr->words);
246 }
247 if (srptr->type == LISTOFWORDS && srptr->wordslist) {
248 for (i = 1; i <= srptr->size; i++) {
249 j = 0;
250 while (srptr->wordslist[i][j]) {
251 tfree(srptr->wordslist[i][j]);
252 j++;
253 }
254 tfree(srptr->wordslist[i]);
255 }
256 tfree(srptr->wordslist);
257 }
258 if (srptr->type == LISTOFINTS && srptr->intlist) {
259 for (i = 1; i <= srptr->size; i++)
260 tfree(srptr->intlist[i]) tfree(srptr->intlist);
261 }
262 if (srptr->type == PRODUCT && srptr->base) {
263 srec_clear(srptr->base);
264 tfree(srptr->base);
265 }
266 if (srptr->type == WORDS || srptr->type == LISTOFWORDS)
267 for (i = 1; i <= srptr->alphabet_size; i++)
268 tfree(srptr->alphabet[i]);
269 if (srptr->type == LABELED) {
270 srec_clear(srptr->labels);
271 tfree(srptr->labels);
272 tfree(srptr->setToLabels);
273 }
274 }
275
276 /* Copy the information in *srptr2 to *srptr1 (same way round as strcpy!)
277 * It is assumed that srptr1 points to a zeroed set-record.
278 */
srec_copy(srec * srptr1,srec * srptr2)279 void srec_copy(srec *srptr1, srec *srptr2)
280 {
281 int i, j, l;
282 srptr1->type = srptr2->type;
283 srptr1->size = srptr2->size;
284 if (srptr1->type == IDENTIFIERS || srptr1->type == STRINGS) {
285 tmalloc(srptr1->names, char *, srptr1->size + 1);
286 for (i = 1; i <= srptr1->size; i++) {
287 tmalloc(srptr1->names[i], char, stringlen(srptr2->names[i]) + 1);
288 strcpy(srptr1->names[i], srptr2->names[i]);
289 }
290 }
291 if (srptr1->type == WORDS) {
292 tmalloc(srptr1->words, gen *, srptr1->size + 1);
293 for (i = 1; i <= srptr1->size; i++) {
294 tmalloc(srptr1->words[i], gen, genstrlen(srptr2->words[i]) + 1);
295 genstrcpy(srptr1->words[i], srptr2->words[i]);
296 }
297 }
298 if (srptr1->type == LISTOFWORDS) {
299 tmalloc(srptr1->wordslist, gen **, srptr1->size + 1);
300 for (i = 1; i <= srptr1->size; i++) {
301 /* First find length of srptr2->wordslist[i] */
302 l = 0;
303 while (srptr2->wordslist[i][l])
304 l++;
305 tmalloc(srptr1->wordslist[i], gen *, l + 1);
306 for (j = 0; j < l; j++) {
307 tmalloc(srptr1->wordslist[i][j], gen,
308 genstrlen(srptr2->wordslist[i][j]) + 1);
309 genstrcpy(srptr1->wordslist[i][j], srptr2->wordslist[i][j]);
310 }
311 srptr1->wordslist[i][l] = 0;
312 }
313 }
314 if (srptr1->type == LISTOFINTS) {
315 tmalloc(srptr1->intlist, int *, srptr1->size + 1);
316 for (i = 1; i <= srptr1->size; i++) {
317 l = srptr2->intlist[i][0];
318 tmalloc(srptr1->intlist[i], int, l + 1);
319 for (j = 0; j <= l; j++) {
320 srptr1->intlist[i][j] = srptr2->intlist[i][j];
321 }
322 }
323 }
324 if (srptr1->type == WORDS || srptr1->type == LISTOFWORDS) {
325 srptr1->alphabet_size = srptr2->alphabet_size;
326 for (i = 1; i <= srptr1->alphabet_size; i++) {
327 tmalloc(srptr1->alphabet[i], char, stringlen(srptr2->alphabet[i]) + 1);
328 strcpy(srptr1->alphabet[i], srptr2->alphabet[i]);
329 }
330 }
331 if (srptr1->type == PRODUCT) {
332 tmalloc(srptr1->base, srec, 1);
333 srec_copy(srptr1->base, srptr2->base);
334 srptr1->arity = srptr2->arity;
335 srptr1->padding = srptr2->padding;
336 }
337 if (srptr1->type == LABELED) {
338 tmalloc(srptr1->labels, srec, 1);
339 srec_copy(srptr1->labels, srptr2->labels);
340 tmalloc(srptr1->setToLabels, setToLabelsType, srptr1->size + 1);
341 for (i = 1; i <= srptr1->size; i++)
342 srptr1->setToLabels[i] = srptr2->setToLabels[i];
343 }
344 }
345
346
347 /* Copy the information in *tableptr2 to *tableptr1 (same way round as strcpy!)
348 * It is assumed that tableptr1 points to a zeroed table_struc.
349 * ne and ns are the sizes of the alphabet and state-set.
350 */
table_copy(table_struc * tableptr1,table_struc * tableptr2,int ne,int ns)351 void table_copy(table_struc *tableptr1, table_struc *tableptr2, int ne, int ns)
352 {
353 int i, j, maxstates, dr, space, *row1, *row2, *ptr1, *ptr2, *ptr2e;
354 if (tableptr2->filename) {
355 tmalloc(tableptr1->filename, char, stringlen(tableptr2->filename) + 1);
356 strcpy(tableptr1->filename, tableptr2->filename);
357 }
358 tableptr1->table_type = tableptr2->table_type;
359 tableptr1->printing_format = tableptr2->printing_format;
360 tableptr1->comment_state_numbers = tableptr2->comment_state_numbers;
361 tableptr1->numTransitions = tableptr2->numTransitions;
362 dr = tableptr1->denserows = tableptr2->denserows;
363 maxstates = tableptr1->maxstates = tableptr2->maxstates;
364
365 if (tableptr1->table_type == DENSE) {
366 tmalloc(tableptr1->table_data_ptr, int *, ne + 1);
367 tmalloc(tableptr1->table_data_ptr[0], int, ne *maxstates);
368 for (i = 1; i <= ne; i++) {
369 row2 = tableptr2->table_data_ptr[i];
370 row1 = tableptr1->table_data_ptr[i] =
371 tableptr1->table_data_ptr[0] + (i - 1) * maxstates - 1;
372 for (j = 1; j <= ns; j++)
373 row1[j] = row2[j];
374 }
375 }
376 else {
377 tmalloc(tableptr1->table_data_ptr, int *, ns + 2);
378 if (dr > 0) {
379 tmalloc(tableptr1->table_data_ptr[0], int, ne *dr);
380 for (i = 1; i <= dr; i++) {
381 row2 = tableptr2->table_data_ptr[i];
382 row1 = tableptr1->table_data_ptr[i] =
383 tableptr1->table_data_ptr[0] + (i - 1) * ne - 1;
384 for (j = 1; j <= ne; j++)
385 row1[j] = row2[j];
386 }
387 if (ns > dr) {
388 space = tableptr2->table_data_ptr[ns + 1] -
389 tableptr2->table_data_ptr[dr + 1];
390 tmalloc(tableptr1->table_data_ptr[dr + 1], int, space + 1);
391 ptr1 = tableptr1->table_data_ptr[dr + 1];
392 }
393 }
394 else {
395 space = tableptr2->table_data_ptr[ns + 1] - tableptr2->table_data_ptr[0];
396 tmalloc(tableptr1->table_data_ptr[0], int, space + 1);
397 ptr1 = tableptr1->table_data_ptr[0];
398 }
399 if (ns > dr) {
400 ptr2 = tableptr2->table_data_ptr[dr + 1];
401 for (i = dr + 1; i <= ns; i++) {
402 tableptr1->table_data_ptr[i] = ptr1;
403 ptr2e = tableptr2->table_data_ptr[i + 1];
404 while (ptr2 < ptr2e)
405 *(ptr1++) = *(ptr2++);
406 }
407 tableptr1->table_data_ptr[ns + 1] = ptr1;
408 }
409 }
410 }
411
412
413 /* Copy the information in *fsaptr2 to *fsaptr1 (same way round as strcpy!)
414 * It is assumed that fsaptr1 points to a zeroed fsa.
415 */
fsa_copy(fsa * fsaptr1,fsa * fsaptr2)416 void fsa_copy(fsa *fsaptr1, fsa *fsaptr2)
417 {
418 int i, ne, ns;
419 fsa_init(fsaptr1);
420 srec_copy(fsaptr1->alphabet, fsaptr2->alphabet);
421 srec_copy(fsaptr1->states, fsaptr2->states);
422 ne = fsaptr1->alphabet->size;
423 ns = fsaptr1->states->size;
424
425 fsaptr1->num_initial = fsaptr2->num_initial;
426 tmalloc(fsaptr1->initial, int, fsaptr1->num_initial + 1);
427 for (i = 1; i <= fsaptr1->num_initial; i++)
428 fsaptr1->initial[i] = fsaptr2->initial[i];
429
430 fsaptr1->num_accepting = fsaptr2->num_accepting;
431 if (ns == 1 || fsaptr1->num_accepting != ns) {
432 tmalloc(fsaptr1->accepting, int, fsaptr1->num_accepting + 1);
433 for (i = 1; i <= fsaptr1->num_accepting; i++)
434 fsaptr1->accepting[i] = fsaptr2->accepting[i];
435 }
436
437 for (i = 0; i < num_kbm_flag_strings; i++)
438 fsaptr1->flags[i] = fsaptr2->flags[i];
439
440 table_copy(fsaptr1->table, fsaptr2->table, ne, ns);
441 }
442
443 /* Deallocate all space used by the table-struc fsaptr */
table_clear(table_struc * tableptr,int ns)444 void table_clear(table_struc *tableptr, int ns)
445 {
446 if (tableptr == 0)
447 return;
448 tfree(tableptr->filename);
449 if (tableptr->table_data_ptr) {
450 tfree(tableptr->table_data_ptr[0]);
451 if (tableptr->table_type == SPARSE && tableptr->denserows > 0 &&
452 tableptr->denserows < ns)
453 tfree(tableptr->table_data_ptr[tableptr->denserows + 1]);
454 tfree(tableptr->table_data_ptr);
455 tfree(tableptr->ctable_data_ptr);
456 tfree(tableptr->table_data_dptr);
457 }
458 }
459
460 /* Deallocate all space used by the fsa *fsaptr */
fsa_clear(fsa * fsaptr)461 void fsa_clear(fsa *fsaptr)
462 {
463 int ns;
464 if (fsaptr == 0)
465 return;
466 srec_clear(fsaptr->states);
467 tfree(fsaptr->states);
468 srec_clear(fsaptr->alphabet);
469 tfree(fsaptr->alphabet);
470 tfree(fsaptr->initial);
471 tfree(fsaptr->accepting);
472 tfree(fsaptr->is_accepting);
473 tfree(fsaptr->is_initial);
474 tfree(fsaptr->is_accessible);
475 ns = fsaptr->states ? fsaptr->states->size : 0;
476 table_clear(fsaptr->table, ns);
477 tfree(fsaptr->table);
478 }
479
480 /* Delete state number stateno from the fsa *fsaptr - works for all fsa's.
481 * Warning - the arrays fsaptr->is_initial, is_accepting and is_accessible
482 * are not updated!
483 */
fsa_delete_state(fsa * fsaptr,int stateno)484 int fsa_delete_state(fsa *fsaptr, int stateno)
485 {
486 int ns, ne, **table, *ptr, *ptr2, *ptr2e, i, j, k, l;
487 srec *srptr;
488
489 if (fsaptr->table->table_type == SPARSE && fsaptr->table->denserows > 0) {
490 fprintf(stderr, "Sorry: fsa_delete_state not available for sparse storage "
491 "with dense rows.\n");
492 return -1;
493 ;
494 }
495
496 if (kbm_print_level >= 3)
497 printf(" #Calling fsa_delete_state on state number %d.\n", stateno);
498 ne = fsaptr->alphabet->size;
499 srptr = fsaptr->states;
500 ns = srptr->size;
501 if (stateno <= 0 || stateno > ns) {
502 fprintf(stderr, "Error in fsa_delete_stateno - invalid state number.\n");
503 return -1;
504 ;
505 }
506 if (srptr->type == IDENTIFIERS || srptr->type == STRINGS) {
507 tfree(srptr->names[stateno]);
508 for (i = stateno; i < ns; i++)
509 srptr->names[i] = srptr->names[i + 1];
510 srptr->names[ns] = 0;
511 }
512 if (srptr->type == WORDS) {
513 tfree(srptr->words[stateno]);
514 for (i = stateno; i < ns; i++)
515 srptr->words[i] = srptr->words[i + 1];
516 srptr->words[ns] = 0;
517 }
518 if (srptr->type == LISTOFWORDS) {
519 j = 0;
520 while (srptr->wordslist[stateno][j]) {
521 tfree(srptr->wordslist[stateno][j]);
522 j++;
523 }
524 tfree(srptr->wordslist[stateno]);
525 for (i = stateno; i < ns; i++)
526 srptr->wordslist[i] = srptr->wordslist[i + 1];
527 srptr->wordslist[ns] = 0;
528 }
529 if (srptr->type == LISTOFINTS) {
530 tfree(srptr->intlist[stateno]);
531 for (i = stateno; i < ns; i++)
532 srptr->intlist[i] = srptr->intlist[i + 1];
533 srptr->intlist[ns] = 0;
534 }
535 if (srptr->type == LABELED)
536 for (i = stateno; i < ns; i++)
537 srptr->setToLabels[i] = srptr->setToLabels[i + 1];
538
539 for (i = 1; i <= fsaptr->num_initial; i++) {
540 k = fsaptr->initial[i];
541 if (k == stateno) {
542 for (j = i; j < fsaptr->num_initial; j++) {
543 l = fsaptr->initial[j + 1];
544 fsaptr->initial[j] = l > stateno ? l - 1 : l;
545 }
546 fsaptr->num_initial--;
547 break;
548 }
549 else if (k > stateno)
550 fsaptr->initial[i] = k - 1;
551 }
552
553 if (fsaptr->num_accepting == ns) {
554 fsaptr->num_accepting--;
555 if (ns == 2) {
556 tmalloc(fsaptr->accepting, int, 2);
557 fsaptr->accepting[1] = 1;
558 }
559 }
560 else
561 for (i = 1; i <= fsaptr->num_accepting; i++) {
562 k = fsaptr->accepting[i];
563 if (k == stateno) {
564 for (j = i; j < fsaptr->num_accepting; j++) {
565 l = fsaptr->accepting[j + 1];
566 fsaptr->accepting[j] = l > stateno ? l - 1 : l;
567 }
568 fsaptr->num_accepting--;
569 break;
570 }
571 else if (k > stateno)
572 fsaptr->accepting[i] = k - 1;
573 }
574
575 fsaptr->flags[NFA] = FALSE;
576 fsaptr->flags[ACCESSIBLE] = FALSE;
577 fsaptr->flags[TRIM] = FALSE;
578 fsaptr->flags[BFS] = FALSE;
579 fsaptr->flags[MINIMIZED] = FALSE;
580
581 table = fsaptr->table->table_data_ptr;
582 if (fsaptr->table->table_type == DENSE) {
583 for (j = 1; j <= ne; j++) {
584 for (i = 1; i < stateno; i++)
585 if (table[j][i] > stateno)
586 table[j][i]--;
587 else if (table[j][i] == stateno)
588 table[j][i] = 0;
589 for (i = stateno; i < ns; i++) {
590 k = table[j][i + 1];
591 table[j][i] = k < stateno ? k : k == stateno ? 0 : k - 1;
592 }
593 }
594 }
595 else {
596 ptr = fsaptr->table->table_data_ptr[0];
597 ptr2 = ptr;
598 for (i = 1; i < stateno; i++) {
599 table[i] = ptr;
600 ptr2e = table[i + 1];
601 while (ptr2 < ptr2e) {
602 if (*(ptr2 + 1) != stateno) {
603 *(ptr++) = *(ptr2++);
604 *(ptr++) = *ptr2 > stateno ? *ptr2 - 1 : *ptr2;
605 ptr2++;
606 }
607 else
608 ptr2 += 2;
609 }
610 }
611 ptr2 = table[stateno + 1];
612 for (i = stateno; i < ns; i++) {
613 table[i] = ptr;
614 ptr2e = table[i + 2];
615 while (ptr2 < ptr2e) {
616 if (*(ptr2 + 1) != stateno) {
617 *(ptr++) = *(ptr2++);
618 *(ptr++) = *ptr2 > stateno ? *ptr2 - 1 : *ptr2;
619 ptr2++;
620 }
621 else
622 ptr2 += 2;
623 }
624 }
625 table[ns] = ptr;
626 }
627 fsaptr->states->size--;
628 return 0;
629 }
630
631 /* permute the states of fsa *fsaptr, using perm - works for all fsa's
632 * perm should be a permutation of the integers 1 to ns - this is not
633 * checked Warning - the arrays fsaptr->is_initial, is_accepting and
634 * is_accessible are not updated. ALSO - perm[0] should be 0 !!
635 */
fsa_permute_states(fsa * fsaptr,int * perm)636 int fsa_permute_states(fsa *fsaptr, int *perm)
637 {
638 int ns, ne, *newtable, **newtableptr, **table, *perminv, *ptr, *ptr2, *ptr2e,
639 i, j;
640 srec *srptr;
641 char **newnames;
642 gen **newwords;
643 gen ***newwordslist;
644 int **newintlist;
645 setToLabelsType *newsetToLabels;
646
647 if (fsaptr->table->table_type == SPARSE && fsaptr->table->denserows > 0) {
648 fprintf(stderr, "Sorry: fsa_permute_state not available for sparse storage "
649 "with dense rows.\n");
650 return -1;
651 }
652 if (kbm_print_level >= 3)
653 printf(" #Calling fsa_permute_states.\n");
654 perm[0] = 0; /* let's make sure! */
655 ne = fsaptr->alphabet->size;
656 srptr = fsaptr->states;
657 ns = srptr->size;
658 if (srptr->type == IDENTIFIERS || srptr->type == STRINGS) {
659 tmalloc(newnames, char *, ns + 1);
660 for (i = 1; i <= ns; i++)
661 newnames[perm[i]] = srptr->names[i];
662 tfree(srptr->names);
663 srptr->names = newnames;
664 }
665 if (srptr->type == WORDS) {
666 tmalloc(newwords, gen *, ns + 1);
667 for (i = 1; i <= ns; i++)
668 newwords[perm[i]] = srptr->words[i];
669 tfree(srptr->words);
670 srptr->words = newwords;
671 }
672 if (srptr->type == LISTOFWORDS) {
673 tmalloc(newwordslist, gen **, ns + 1);
674 for (i = 1; i <= ns; i++)
675 newwordslist[perm[i]] = srptr->wordslist[i];
676 tfree(srptr->wordslist);
677 srptr->wordslist = newwordslist;
678 }
679 if (srptr->type == LISTOFINTS) {
680 tmalloc(newintlist, int *, ns + 1);
681 for (i = 1; i <= ns; i++)
682 newintlist[perm[i]] = srptr->intlist[i];
683 tfree(srptr->intlist);
684 srptr->intlist = newintlist;
685 }
686 if (srptr->type == LABELED) {
687 tmalloc(newsetToLabels, setToLabelsType, ns + 1);
688 for (i = 1; i <= ns; i++)
689 newsetToLabels[perm[i]] = srptr->setToLabels[i];
690 tfree(srptr->setToLabels);
691 srptr->setToLabels = newsetToLabels;
692 }
693
694 if (fsaptr->num_initial != ns) {
695 tmalloc(fsaptr->is_initial, boolean, ns + 1);
696 for (i = 1; i <= ns; i++)
697 fsaptr->is_initial[i] = FALSE;
698 for (i = 1; i <= fsaptr->num_initial; i++)
699 fsaptr->is_initial[perm[fsaptr->initial[i]]] = TRUE;
700 j = 0;
701 for (i = 1; i <= ns; i++)
702 if (fsaptr->is_initial[i])
703 fsaptr->initial[++j] = i;
704 tfree(fsaptr->is_initial);
705 }
706
707 if (fsaptr->num_accepting != ns) {
708 tmalloc(fsaptr->is_accepting, boolean, ns + 1);
709 for (i = 1; i <= ns; i++)
710 fsaptr->is_accepting[i] = FALSE;
711 for (i = 1; i <= fsaptr->num_accepting; i++)
712 fsaptr->is_accepting[perm[fsaptr->accepting[i]]] = TRUE;
713 j = 0;
714 for (i = 1; i <= ns; i++)
715 if (fsaptr->is_accepting[i])
716 fsaptr->accepting[++j] = i;
717 tfree(fsaptr->is_accepting);
718 }
719
720 fsaptr->flags[BFS] = FALSE;
721
722 table = fsaptr->table->table_data_ptr;
723 if (fsaptr->table->table_type == DENSE) {
724 perm[0] = 0; /* just to make sure! */
725 tmalloc(newtable, int, ns *ne);
726 for (j = 1; j <= ne; j++) {
727 ptr = newtable + (j - 1) * ns - 1;
728 for (i = 1; i <= ns; i++)
729 ptr[perm[i]] = perm[table[j][i]];
730 table[j] = ptr;
731 }
732 tfree(fsaptr->table->table_data_ptr[0]);
733 fsaptr->table->table_data_ptr[0] = newtable;
734 }
735 else {
736 /* We need the inverse of perm in this case */
737 tmalloc(perminv, int, ns + 1);
738 for (i = 1; i <= ns; i++)
739 perminv[perm[i]] = i;
740 tmalloc(newtable, int, table[ns + 1] - table[1]);
741 tmalloc(newtableptr, int *, ns + 2);
742 ptr = newtable;
743 for (i = 1; i <= ns; i++) {
744 newtableptr[i] = ptr;
745 ptr2 = table[perminv[i]];
746 ptr2e = table[perminv[i] + 1];
747 while (ptr2 < ptr2e) {
748 *(ptr++) = *(ptr2++);
749 *(ptr++) = perm[*(ptr2++)];
750 }
751 }
752 newtableptr[ns + 1] = ptr;
753 tfree(perminv);
754 tfree(fsaptr->table->table_data_ptr[0]);
755 tfree(fsaptr->table->table_data_ptr);
756 fsaptr->table->table_data_ptr = newtableptr;
757 fsaptr->table->table_data_ptr[0] = newtable;
758 }
759 return 0;
760 }
761
762 /* If *fsaptr is an rws (rewriting-system) automaton, then it may have
763 * negative targets, which point to reduction equations.
764 * This function simply replaces all of these targets by 0, to make it
765 * into a conventional fsa.
766 */
fsa_clear_rws(fsa * fsaptr)767 int fsa_clear_rws(fsa *fsaptr)
768 {
769 int ns, ne, **table, *ptr, *ptr2, *ptr2e, i, j;
770
771 if (fsaptr->table->table_type == SPARSE && fsaptr->table->denserows > 0) {
772 fprintf(stderr, "Sorry: fsa_clear_rws not available for sparse storage "
773 "with dense rows.\n");
774 return -1;
775 }
776 if (fsaptr->flags[RWS] == FALSE)
777 return 0;
778
779 ne = fsaptr->alphabet->size;
780 ns = fsaptr->states->size;
781
782 table = fsaptr->table->table_data_ptr;
783 if (fsaptr->table->table_type == DENSE) {
784 for (j = 1; j <= ne; j++)
785 for (i = 1; i <= ns; i++)
786 if (table[j][i] < 0)
787 table[j][i] = 0;
788 }
789 else {
790 ptr = table[1];
791 for (i = 1; i <= ns; i++) {
792 ptr2 = table[i];
793 ptr2e = table[i + 1];
794 table[i] = ptr;
795 while (ptr2 < ptr2e) {
796 if (*(ptr2 + 1) > 0) {
797 *(ptr++) = *(ptr2++);
798 *(ptr++) = *(ptr2++);
799 }
800 else
801 ptr2 += 2;
802 }
803 }
804 table[ns + 1] = ptr;
805 }
806
807 fsaptr->flags[RWS] = FALSE;
808 return 0;
809 }
810
811 /* Make the fsa *fsaptr accessible - i.e. all states reachable from
812 * start-state
813 */
fsa_make_accessible(fsa * fsaptr)814 int fsa_make_accessible(fsa *fsaptr)
815 {
816 int ns, i;
817 storage_type st = fsaptr->table->table_type;
818 fsa *temp;
819
820 if (st == SPARSE && fsaptr->table->denserows > 0) {
821 fprintf(stderr, "Sorry: fsa_make_accessible unavailable for sparse storage "
822 "with dense rows.\n");
823 return -1;
824 }
825 if (kbm_print_level >= 3)
826 printf(" #Calling fsa_make_accessible.\n");
827 if (fsaptr->flags[MINIMIZED] || fsaptr->flags[ACCESSIBLE] ||
828 fsaptr->flags[TRIM])
829 return 0;
830
831 if (fsaptr->flags[RWS])
832 fsa_clear_rws(fsaptr);
833
834 ns = fsaptr->states->size;
835
836 if (fsaptr->num_initial == ns) {
837 fsaptr->flags[ACCESSIBLE] = TRUE;
838 return 0;
839 }
840
841 /* In the deterministic case, we do it by and-ing it with itself - should
842 * write separate code for this really, but it hardly seems worth it. This
843 * works faster than deleting redundant states.
844 */
845 if (fsaptr->flags[DFA] && fsaptr->states->type != LABELED) {
846 temp = fsa_and(fsaptr, fsaptr, st, TRUE, "/tmp/fsa_and_xxx");
847 fsa_copy(fsaptr, temp);
848 fsa_clear(temp);
849 tfree(temp);
850 return 0;
851 }
852
853 /* Now find the list of states accessible from the start-state. */
854 fsa_set_is_accessible(fsaptr);
855
856 /* Now delete inaccessible states */
857 for (i = ns; i >= 1; i--)
858 if (!fsaptr->is_accessible[i])
859 fsa_delete_state(fsaptr, i);
860
861 tfree(fsaptr->is_accessible);
862 return 0;
863 }
864
865 /* Minimize the fsa *fsaptr. */
fsa_minimize(fsa * fsaptr)866 int fsa_minimize(fsa *fsaptr)
867 {
868 int *block_numa, *block_numb, *block_swap, i, j, k, l, len, *ptr, *ptr2,
869 *ptr2e, *ht_ptr, ne, ns_orig, **table, ns_final, ns_new, num_iterations;
870 hash_table ht;
871 boolean fixed, acc;
872
873 if (fsaptr->table->table_type == SPARSE && fsaptr->table->denserows > 0) {
874 fprintf(stderr, "Sorry: fsa_minimize unavailable for sparse storage with "
875 "dense rows.\n");
876 return -1;
877 }
878
879 if (kbm_print_level >= 3)
880 printf(" #Calling fsa_minimize.\n");
881 if (!fsaptr->flags[DFA]) {
882 fprintf(stderr, "Error: fsa_minimize only applies to DFA's.\n");
883 return -1;
884 }
885 if (fsaptr->flags[MINIMIZED])
886 return 0;
887
888 if (fsaptr->flags[RWS])
889 fsa_clear_rws(fsaptr);
890
891 acc = fsaptr->flags[ACCESSIBLE] || fsaptr->flags[TRIM];
892 if (!acc)
893 fsa_set_is_accessible(fsaptr);
894
895 ns_orig = fsaptr->states->size;
896 if (ns_orig == 0) {
897 fsaptr->flags[TRIM] = TRUE;
898 fsaptr->flags[MINIMIZED] = TRUE;
899 tfree(fsaptr->is_accessible);
900 return 0;
901 }
902
903 /* First throw away any existing structure on the state-set. */
904 srec_clear(fsaptr->states);
905 fsaptr->states->type = SIMPLE;
906 ne = fsaptr->alphabet->size;
907 table = fsaptr->table->table_data_ptr;
908
909 tmalloc(block_numa, int, ns_orig + 1);
910 tmalloc(block_numb, int, ns_orig + 1);
911 for (i = 0; i <= ns_orig; i++)
912 block_numb[i] = 0;
913 /* Start with block_numa equal to the accept/reject division
914 * Remember that state/block number 0 is always failure with no hope.
915 */
916 if (fsaptr->num_accepting == ns_orig) {
917 block_numa[0] = 0;
918 for (i = 1; i <= ns_orig; i++)
919 if (acc || fsaptr->is_accessible[i])
920 block_numa[i] = 1;
921 else
922 block_numa[i] = 0;
923 }
924 else {
925 for (i = 0; i <= ns_orig; i++)
926 block_numa[i] = 0;
927 for (i = 1; i <= fsaptr->num_accepting; i++)
928 if (acc || fsaptr->is_accessible[fsaptr->accepting[i]])
929 block_numa[fsaptr->accepting[i]] = 1;
930 }
931
932 fixed = fsaptr->table->table_type == DENSE;
933
934 ns_new = 1;
935 num_iterations = 0;
936 /* The main refinement loop follows. */
937 do {
938 num_iterations++;
939 ns_final = ns_new;
940 /* Turn off excessive printing at this point */
941 j = kbm_print_level;
942 kbm_print_level = 1;
943 hash_init(&ht, fixed, ne + 1, 0, 0);
944 kbm_print_level = j;
945 if (kbm_print_level >= 3)
946 printf(" #Iterating - number of state categories = %d.\n", ns_new);
947 block_numb[0] = 0;
948 for (i = 1; i <= ns_orig; i++)
949 if (acc || fsaptr->is_accessible[i]) {
950 /* Insert the encoded form of the transitions from state i into the
951 * hashtable preceded by the current block number of i.
952 */
953 len = fixed ? ne + 1 : table[i + 1] - table[i] + 1;
954 ptr = ht.current_ptr;
955 *ptr = block_numa[i];
956 if (fixed) {
957 for (j = 1; j < len; j++)
958 ptr[j] = block_numa[table[j][i]];
959 l = len;
960 }
961 else {
962 l = 0;
963 for (j = 1; j < len; j += 2) {
964 k = block_numa[table[i][j]];
965 if (k > 0) {
966 ptr[++l] = table[i][j - 1];
967 ptr[++l] = k;
968 }
969 }
970 if (l > 0 || *ptr > 0)
971 l++;
972 /* For technical reasons, we want the zero record to be empty */
973 }
974 block_numb[i] = hash_locate(&ht, l);
975 if (block_numb[i] == -1)
976 return -1;
977 }
978 else
979 block_numb[i] = 0;
980 ns_new = ht.num_recs;
981 block_swap = block_numa;
982 block_numa = block_numb;
983 block_numb = block_swap;
984 if (ns_new > ns_final)
985 hash_clear(&ht);
986 } while (ns_new > ns_final);
987
988 if (kbm_print_level >= 4) { /* print out old-new state correspondence */
989 printf("Old State NewState\n");
990 for (i = 1; i <= ns_orig; i++)
991 printf(" %6d %6d\n", i, block_numa[i]);
992 }
993
994 /* At this stage, either ns_final = ns_new, or the fsa has empty accepted
995 * language, ns_new=0 and ns_final=1.
996 */
997
998 fsaptr->flags[TRIM] = TRUE;
999 fsaptr->flags[MINIMIZED] = TRUE;
1000
1001 if (ns_new == 0) {
1002 /* This is the awkward case of no states - always causes problems! */
1003 fsaptr->states->size = 0;
1004 fsaptr->num_initial = 0;
1005 tfree(fsaptr->initial);
1006 fsaptr->num_accepting = 0;
1007 tfree(fsaptr->accepting);
1008 tfree(fsaptr->table->table_data_ptr[0]);
1009 tfree(fsaptr->table->table_data_ptr);
1010 }
1011 else if (ns_final < ns_orig) {
1012 /* Re-define the fsa fields */
1013 fsaptr->states->size = ns_final;
1014
1015 fsaptr->initial[1] = block_numa[fsaptr->initial[1]];
1016
1017 if (fsaptr->num_accepting == ns_orig) {
1018 fsaptr->num_accepting = ns_final;
1019 if (ns_final == 1) {
1020 tmalloc(fsaptr->accepting, int, 2);
1021 fsaptr->accepting[1] = 1;
1022 }
1023 }
1024 else {
1025 tmalloc(fsaptr->is_accepting, boolean, ns_final + 1);
1026 for (i = 1; i <= ns_final; i++)
1027 fsaptr->is_accepting[i] = FALSE;
1028 for (i = 1; i <= fsaptr->num_accepting; i++)
1029 fsaptr->is_accepting[block_numa[fsaptr->accepting[i]]] = TRUE;
1030 fsaptr->num_accepting = 0;
1031 for (i = 1; i <= ns_final; i++)
1032 if (fsaptr->is_accepting[i])
1033 fsaptr->num_accepting++;
1034 tfree(fsaptr->accepting);
1035 tmalloc(fsaptr->accepting, int, fsaptr->num_accepting + 1);
1036 j = 0;
1037 for (i = 1; i <= ns_final; i++)
1038 if (fsaptr->is_accepting[i])
1039 fsaptr->accepting[++j] = i;
1040 tfree(fsaptr->is_accepting);
1041 }
1042
1043 /* Finally copy the transition table data from the hash-table back to the
1044 * fsa */
1045 tfree(fsaptr->table->table_data_ptr[0]);
1046 tfree(fsaptr->table->table_data_ptr);
1047 if (fixed) {
1048 fsa_table_init(fsaptr->table, ns_final, ne);
1049 table = fsaptr->table->table_data_ptr;
1050 for (i = 1; i <= ns_final; i++) {
1051 ht_ptr = hash_rec(&ht, i);
1052 for (j = 1; j <= ne; j++)
1053 table[j][i] = ht_ptr[j];
1054 }
1055 }
1056 else {
1057 tmalloc(fsaptr->table->table_data_ptr, int *, ns_final + 2);
1058 tmalloc(fsaptr->table->table_data_ptr[0], int, ht.tot_space - ns_final);
1059 table = fsaptr->table->table_data_ptr;
1060 table[1] = ptr = table[0];
1061 for (i = 1; i <= ns_final; i++) {
1062 ht_ptr = hash_rec(&ht, i);
1063 ptr2 = ht_ptr + 1;
1064 ptr2e = ht_ptr + hash_rec_len(&ht, i) - 1;
1065 while (ptr2 <= ptr2e)
1066 *(ptr++) = *(ptr2++);
1067 table[i + 1] = ptr;
1068 }
1069 }
1070 }
1071 hash_clear(&ht);
1072 tfree(block_numa);
1073 tfree(block_numb);
1074 tfree(fsaptr->is_accessible);
1075 if (kbm_print_level >= 3)
1076 printf(" #Number of iterations = %d.\n", num_iterations);
1077 return 0;
1078 }
1079
1080 /* This is the minimization function for fsa's which might have more than
1081 * two categories of states.
1082 * We use the labeled set-record type to identify the categories, so *fsaptr
1083 * must have state-set of labeled type.
1084 * The accepting states should be a union of some of the state
1085 * categories, or else the accepting states of the result will be
1086 * meaningless!
1087 */
fsa_labeled_minimize(fsa * fsaptr)1088 int fsa_labeled_minimize(fsa *fsaptr)
1089 {
1090 int *block_numa, *block_numb, *block_swap, i, j, k, l, len, *ptr, *ptr2,
1091 *ptr2e, *ht_ptr, ne, ns_orig, **table, ns_final, ns_new, num_iterations;
1092 hash_table ht;
1093 boolean fixed, *occurs, acc;
1094
1095 if (fsaptr->table->table_type == SPARSE && fsaptr->table->denserows > 0) {
1096 fprintf(stderr, "Sorry: fsa_labeled_minimize unavailable for sparse "
1097 "storage with dense rows.\n");
1098 return -1;
1099 }
1100 if (kbm_print_level >= 3)
1101 printf(" #Calling fsa_labeled_minimize.\n");
1102 if (!fsaptr->flags[DFA]) {
1103 fprintf(stderr, "Error: fsa_labeled_minimize only applies to DFA's.\n");
1104 return -1;
1105 }
1106
1107 if (fsaptr->states->type != LABELED) {
1108 fprintf(
1109 stderr,
1110 "Error: in fsa_labeled_minimize state-set must have type labeled.\n");
1111 return -1;
1112 }
1113
1114 if (fsaptr->flags[RWS])
1115 fsa_clear_rws(fsaptr);
1116
1117 acc = fsaptr->flags[ACCESSIBLE] || fsaptr->flags[TRIM];
1118 if (!acc)
1119 fsa_set_is_accessible(fsaptr);
1120
1121 ne = fsaptr->alphabet->size;
1122 table = fsaptr->table->table_data_ptr;
1123 ns_orig = fsaptr->states->size;
1124 if (ns_orig == 0) {
1125 tfree(fsaptr->is_accessible);
1126 return 0;
1127 }
1128
1129 /* Start with block_numa equal to the subdivision defined by the labeling. */
1130 tmalloc(occurs, boolean, fsaptr->states->labels->size + 1);
1131 for (i = 1; i <= fsaptr->states->labels->size; i++)
1132 occurs[i] = FALSE;
1133 tmalloc(block_numa, int, ns_orig + 1);
1134 tmalloc(block_numb, int, ns_orig + 1);
1135 for (i = 0; i <= ns_orig; i++)
1136 block_numb[i] = 0;
1137 ns_new = 0;
1138 block_numa[0] = 0; /* The zero state is always regarded as having label 0 */
1139 for (i = 1; i <= ns_orig; i++)
1140 if (acc || fsaptr->is_accessible[i]) {
1141 j = fsaptr->states->setToLabels[i];
1142 if (j > 0 && !occurs[j]) {
1143 occurs[j] = TRUE;
1144 ns_new++;
1145 }
1146 block_numa[i] = j;
1147 }
1148 else
1149 block_numa[i] = 0;
1150 tfree(occurs);
1151 if (ns_new == 0)
1152 ns_new = 1; /* a patch for the case when there are no labels */
1153
1154 fixed = fsaptr->table->table_type == DENSE;
1155
1156 num_iterations = 0;
1157 /* The main refinement loop follows. */
1158 do {
1159 num_iterations++;
1160 ns_final = ns_new;
1161 /* Turn off excessive printing at this point */
1162 j = kbm_print_level;
1163 kbm_print_level = 1;
1164 hash_init(&ht, fixed, ne + 1, 0, 0);
1165 kbm_print_level = j;
1166 if (kbm_print_level >= 3)
1167 printf(" #Iterating - number of state categories = %d.\n", ns_new);
1168 block_numb[0] = 0;
1169 for (i = 1; i <= ns_orig; i++)
1170 if (acc || fsaptr->is_accessible[i]) {
1171 /* Insert the encoded form of the transitions from state i into the
1172 * hashtable preceded by the current block number of i.
1173 */
1174 len = fixed ? ne + 1 : table[i + 1] - table[i] + 1;
1175 ptr = ht.current_ptr;
1176 *ptr = block_numa[i];
1177 if (fixed) {
1178 for (j = 1; j < len; j++)
1179 ptr[j] = block_numa[table[j][i]];
1180 l = len;
1181 }
1182 else {
1183 l = 0;
1184 for (j = 1; j < len; j += 2) {
1185 k = block_numa[table[i][j]];
1186 if (k > 0) {
1187 ptr[++l] = table[i][j - 1];
1188 ptr[++l] = k;
1189 }
1190 }
1191 if (l > 0 || *ptr > 0)
1192 l++;
1193 /* For technical reasons, we want the zero record to be empty */
1194 }
1195 block_numb[i] = hash_locate(&ht, l);
1196 if (block_numb[i] == -1)
1197 return -1;
1198 }
1199 else
1200 block_numb[i] = 0;
1201 ns_new = ht.num_recs;
1202 block_swap = block_numa;
1203 block_numa = block_numb;
1204 block_numb = block_swap;
1205 if (ns_new > ns_final || num_iterations == 1)
1206 hash_clear(&ht);
1207 } while (ns_new > ns_final || num_iterations == 1);
1208 /* We must have at least two iterations, because the first time through
1209 * we have the lables rather than the states in the transition table.
1210 */
1211
1212 /* At this stage, either ns_final = ns_new, or the fsa has empty accepted
1213 * language, ns_new=0 and ns_final=1.
1214 */
1215
1216 fsaptr->flags[ACCESSIBLE] = TRUE;
1217
1218 if (ns_new == 0) {
1219 /* This is the awkward case of no states - always causes problems! */
1220 fsaptr->states->size = 0;
1221 fsaptr->num_initial = 0;
1222 tfree(fsaptr->initial);
1223 fsaptr->num_accepting = 0;
1224 tfree(fsaptr->accepting);
1225 tfree(fsaptr->table->table_data_ptr[0]);
1226 tfree(fsaptr->table->table_data_ptr);
1227 }
1228 else if (ns_final < ns_orig) {
1229 /* Re-define the fsa fields */
1230 fsaptr->states->size = ns_final;
1231
1232 fsaptr->initial[1] = block_numa[fsaptr->initial[1]];
1233
1234 for (i = 1; i <= ns_orig; i++)
1235 block_numb[block_numa[i]] = fsaptr->states->setToLabels[i];
1236 for (i = 1; i <= ns_final; i++)
1237 fsaptr->states->setToLabels[i] = block_numb[i];
1238
1239 if (fsaptr->num_accepting == ns_orig) {
1240 fsaptr->num_accepting = ns_final;
1241 if (ns_final == 1) {
1242 tmalloc(fsaptr->accepting, int, 2);
1243 fsaptr->accepting[1] = 1;
1244 }
1245 }
1246 else {
1247 tmalloc(fsaptr->is_accepting, boolean, ns_final + 1);
1248 for (i = 1; i <= ns_final; i++)
1249 fsaptr->is_accepting[i] = FALSE;
1250 for (i = 1; i <= fsaptr->num_accepting; i++)
1251 fsaptr->is_accepting[block_numa[fsaptr->accepting[i]]] = TRUE;
1252 fsaptr->num_accepting = 0;
1253 for (i = 1; i <= ns_final; i++)
1254 if (fsaptr->is_accepting[i])
1255 fsaptr->num_accepting++;
1256 tfree(fsaptr->accepting);
1257 tmalloc(fsaptr->accepting, int, fsaptr->num_accepting + 1);
1258 j = 0;
1259 for (i = 1; i <= ns_final; i++)
1260 if (fsaptr->is_accepting[i])
1261 fsaptr->accepting[++j] = i;
1262 tfree(fsaptr->is_accepting);
1263 }
1264
1265 /* Finally copy the transition table data from the hash-table back to the
1266 * fsa */
1267 tfree(fsaptr->table->table_data_ptr[0]);
1268 tfree(fsaptr->table->table_data_ptr);
1269 if (fixed) {
1270 fsa_table_init(fsaptr->table, ns_final, ne);
1271 table = fsaptr->table->table_data_ptr;
1272 for (i = 1; i <= ns_final; i++) {
1273 ht_ptr = hash_rec(&ht, i);
1274 for (j = 1; j <= ne; j++)
1275 table[j][i] = ht_ptr[j];
1276 }
1277 }
1278 else {
1279 tmalloc(fsaptr->table->table_data_ptr, int *, ns_final + 2);
1280 tmalloc(fsaptr->table->table_data_ptr[0], int, ht.tot_space - ns_final);
1281 table = fsaptr->table->table_data_ptr;
1282 table[1] = ptr = table[0];
1283 for (i = 1; i <= ns_final; i++) {
1284 ht_ptr = hash_rec(&ht, i);
1285 ptr2 = ht_ptr + 1;
1286 ptr2e = ht_ptr + hash_rec_len(&ht, i) - 1;
1287 while (ptr2 <= ptr2e)
1288 *(ptr++) = *(ptr2++);
1289 table[i + 1] = ptr;
1290 }
1291 }
1292 }
1293 hash_clear(&ht);
1294 tfree(block_numa);
1295 tfree(block_numb);
1296 tfree(fsaptr->is_accessible);
1297 if (kbm_print_level >= 3)
1298 printf(" #Number of iterations = %d.\n", num_iterations);
1299 return 0;
1300 }
1301
1302
1303 /* Put the fsa *fsapt into bfs form. */
fsa_bfs(fsa * fsaptr)1304 int fsa_bfs(fsa *fsaptr)
1305 {
1306 int ns, ne, *perm, *perminv, **table, ct, i, j, s, t;
1307 boolean *got, dense;
1308
1309 if (fsaptr->table->table_type == SPARSE && fsaptr->table->denserows > 0) {
1310 fprintf(stderr,
1311 "Sorry: fsa_bfs unavailable for sparse storage with dense rows.\n");
1312 return -1;
1313 }
1314 if (kbm_print_level >= 3)
1315 printf(" #Calling fsa_bfs.\n");
1316 if (!fsaptr->flags[DFA]) {
1317 fprintf(stderr, "Error: fsa_bfs only applies to DFA's.\n");
1318 return -1;
1319 }
1320 if (fsaptr->flags[BFS])
1321 return 0;
1322
1323 fsa_make_accessible(fsaptr);
1324
1325 if (fsaptr->flags[RWS])
1326 fsa_clear_rws(fsaptr);
1327
1328 ne = fsaptr->alphabet->size;
1329 ns = fsaptr->states->size;
1330 if (ns == 0)
1331 return 0;
1332
1333 dense = fsaptr->table->table_type == DENSE;
1334 table = fsaptr->table->table_data_ptr;
1335
1336 tmalloc(got, boolean, ns + 1);
1337 for (i = 1; i <= ns; i++)
1338 got[i] = FALSE;
1339 tmalloc(perm, int, ns + 1);
1340 perm[0] = 0;
1341 perm[1] = fsaptr->initial[1];
1342 got[perm[1]] = TRUE;
1343 ct = 1;
1344 i = 1;
1345 while (i <= ct) {
1346 s = perm[i];
1347 for (j = 1; j <= ne; j++) {
1348 t = target(dense, table, j, s, 0);
1349 if (t > 0 && !got[t]) {
1350 perm[++ct] = t;
1351 got[t] = TRUE;
1352 }
1353 }
1354 i++;
1355 }
1356
1357 tfree(got);
1358 /* The inverse of perm is what is required */
1359 tmalloc(perminv, int, ns + 1);
1360 for (i = 0; i <= ns; i++)
1361 perminv[perm[i]] = i;
1362 tfree(perm);
1363 fsa_permute_states(fsaptr, perminv);
1364 tfree(perminv);
1365 fsaptr->flags[BFS] = TRUE;
1366 return 0;
1367 }
1368
1369 /* Count the size of the accepted language of the fsa *fsaptr.
1370 * Return this size, or -2 if infinite.
1371 */
fsa_count(fsa * fsaptr)1372 int fsa_count(fsa *fsaptr)
1373 {
1374 int i, j, ct, ne, ns, **table, dr, *in_degree, *ordered_state_list,
1375 *num_acc_words, cstate, im;
1376 boolean dense;
1377
1378 if (!fsaptr->flags[DFA]) {
1379 fprintf(stderr, "Error: fsa_count only applies to DFA's.\n");
1380 return -1;
1381 }
1382 if (!fsaptr->flags[TRIM])
1383 if (fsa_minimize(fsaptr) == -1)
1384 return -1;
1385
1386 ne = fsaptr->alphabet->size;
1387 ns = fsaptr->states->size;
1388 if (ns == 0)
1389 return 0;
1390
1391 dr = fsaptr->table->denserows;
1392
1393 /* We first count the number of edges going into each state */
1394 tmalloc(in_degree, int, ns + 1);
1395 for (i = 1; i <= ns; i++)
1396 in_degree[i] = 0;
1397 dense = fsaptr->table->table_type == DENSE;
1398 table = fsaptr->table->table_data_ptr;
1399 for (i = 1; i <= ns; i++)
1400 for (j = 1; j <= ne; j++) {
1401 im = target(dense, table, j, i, dr);
1402 if (im > 0)
1403 in_degree[im]++;
1404 }
1405
1406 /* Now we try to order the states so that if state s <= state t, then there
1407 * is no path from state t to state s. If this is not possible, then the
1408 * accepted language must be infinite.
1409 */
1410 cstate = fsaptr->initial[1];
1411 if (in_degree[cstate] > 0) {
1412 tfree(in_degree);
1413 return -2;
1414 }
1415 tmalloc(ordered_state_list, int, ns + 1);
1416 ordered_state_list[1] = cstate;
1417
1418 ct = 1;
1419 i = 0;
1420 while (++i <= ct) {
1421 cstate = ordered_state_list[i];
1422 for (j = 1; j <= ne; j++) {
1423 im = target(dense, table, j, cstate, dr);
1424 if (im > 0) {
1425 in_degree[im]--;
1426 if (in_degree[im] == 0)
1427 ordered_state_list[++ct] = im;
1428 }
1429 }
1430 }
1431
1432 if (ct != ns) {
1433 tfree(in_degree) tfree(ordered_state_list) return -2;
1434 }
1435
1436 /* We have built the list, so the accepted language is finite. Now we work
1437 * backwards through the list, calculating the number of accepted words
1438 * starting at that state.
1439 * We might as well use the same space as was used by in_degree, which
1440 * is no longer needed.
1441 */
1442 fsa_set_is_accepting(fsaptr);
1443 num_acc_words = in_degree;
1444 for (i = ns; i >= 1; i--) {
1445 cstate = ordered_state_list[i];
1446 num_acc_words[cstate] = 0;
1447 for (j = 1; j <= ne; j++) {
1448 im = target(dense, table, j, cstate, dr);
1449 if (im > 0)
1450 num_acc_words[cstate] += num_acc_words[im];
1451 }
1452 if (fsaptr->is_accepting[cstate])
1453 num_acc_words[cstate]++;
1454 }
1455
1456 ct = num_acc_words[fsaptr->initial[1]];
1457 tfree(in_degree) tfree(ordered_state_list)
1458 tfree(fsaptr->is_accepting) return ct;
1459 }
1460
1461 /* Enumerate the subset of the language of the finite state automaton *fsaptr,
1462 * consisting of those words having length l satisfying min <= l <= max.
1463 * Since there is no point in storing these words currently, they are
1464 * printed out to the file wfile, with all but the last one to be printed
1465 * followed by a comma and carriage return.
1466 * 1 is returned if some words are found - otherwise 0.
1467 * If putcomma is true, then the first word to be printed is preceded by comma
1468 * and carriage-return (to handle the case when this function is called
1469 * repeatedly).
1470 * If stateno is 1, then the number of the accept state reched by an
1471 * accepted word is printed.
1472 * If stateno is 2, then fsaptr->states should have type 'labeled', and
1473 * the labels of the accept-states reached by the words are printed.
1474 */
fsa_enumerate(FILE * wfile,fsa * fsaptr,int min,int max,boolean putcomma,int stateno)1475 int fsa_enumerate(FILE *wfile, fsa *fsaptr, int min, int max, boolean putcomma,
1476 int stateno)
1477 {
1478 int i, g1, g2, ne, ngens, ngens1 = 0, **table, dr, *cword, firste, clength,
1479 clength1, clength2, cstate, im, *statelist;
1480 boolean dense, done, backtrack, foundword, prod, numbers;
1481 gen *cword1 = 0, *cword2 = 0;
1482 char **names = 0;
1483
1484 if (!fsaptr->flags[DFA]) {
1485 fprintf(stderr, "Error: fsa_enumerate only applies to DFA's.\n");
1486 return -1;
1487 }
1488
1489 if (stateno == 2 && fsaptr->states->type != LABELED) {
1490 fprintf(stderr,
1491 "Error: in fsa_enumerate state-set must have type labeled.\n");
1492 return -1;
1493 }
1494
1495 if (fsaptr->num_initial == 0)
1496 return 0;
1497
1498 ne = fsaptr->alphabet->size;
1499
1500 dr = fsaptr->table->denserows;
1501
1502 dense = fsaptr->table->table_type == DENSE;
1503 table = fsaptr->table->table_data_ptr;
1504
1505 tmalloc(cword, int, max + 1);
1506 /* to hold the current word in the enumeration */
1507
1508 /* "names" will be used to store the symbols used for printing. If no natural
1509 * names are available, then we just use the numbers of the edges.
1510 */
1511 prod = fsaptr->alphabet->type == PRODUCT;
1512 if (prod) {
1513 if (fsaptr->alphabet->arity != 2) {
1514 fprintf(stderr,
1515 "Sorry can only cope with two-variable product alphabets.\n");
1516 return 0;
1517 }
1518 ngens = fsaptr->alphabet->base->size;
1519 ngens1 = ngens + 1;
1520 numbers = fsaptr->alphabet->base->type == SIMPLE ||
1521 fsaptr->alphabet->base->type == LABELED ||
1522 fsaptr->alphabet->base->type == WORDS ||
1523 fsaptr->alphabet->base->type == LISTOFWORDS ||
1524 fsaptr->alphabet->base->type == LISTOFINTS;
1525 if (!numbers) {
1526 names = fsaptr->alphabet->base->names;
1527 tmalloc(names[ngens1], char, 2);
1528 strcpy(names[ngens1], "_");
1529 }
1530 tmalloc(cword1, gen, max + 1);
1531 tmalloc(cword2, gen, max + 1);
1532 /* These are used for the two components of the word cword =
1533 * [cword1,cword2].
1534 */
1535 }
1536 else {
1537 numbers = fsaptr->alphabet->type == SIMPLE ||
1538 fsaptr->alphabet->type == LABELED ||
1539 fsaptr->alphabet->type == WORDS ||
1540 fsaptr->alphabet->type == LISTOFWORDS ||
1541 fsaptr->alphabet->type == LISTOFINTS;
1542 if (!numbers)
1543 names = fsaptr->alphabet->names;
1544 }
1545 if (numbers) { /* define the integral names. */
1546 tmalloc(names, char *, ne + 1);
1547 for (i = 1; i <= ne; i++) {
1548 tmalloc(names[i], char, int_len(i) + 1);
1549 sprintf(names[i], "%d", i);
1550 }
1551 }
1552
1553 *kbm_buffer = '\0';
1554 tmalloc(statelist, int, max + 1);
1555 /* this is used to store the state history on scanning the current word. */
1556 for (i = 0; i <= max; i++)
1557 cword[i] = 0;
1558 clength = 0;
1559 statelist[0] = fsaptr->initial[1];
1560 fsa_set_is_accepting(fsaptr);
1561 done = FALSE;
1562 foundword = FALSE;
1563 /* Backtrack search can now begin */
1564 while (!done) {
1565 /* first see if we want the current word - if so, print it */
1566 if (clength >= min && fsaptr->is_accepting[statelist[clength]]) {
1567 if (putcomma || foundword)
1568 fprintf(wfile, ",\n");
1569 if (stateno)
1570 add_to_buffer(0, "[");
1571 foundword = TRUE;
1572 if (prod) { /* split word into components and print them */
1573 clength1 = clength2 = 0;
1574 for (i = 0; i < clength; i++) {
1575 g1 = (cword[i] - 1) / ngens1 + 1;
1576 g2 = (cword[i] - 1) % ngens1 + 1;
1577 /*if (g1<ngens1)*/ cword1[clength1++] = g1;
1578 /*if (g2<ngens1)*/ cword2[clength2++] = g2;
1579 }
1580 cword1[clength1] = 0;
1581 cword2[clength2] = 0;
1582 add_to_buffer(0, " [");
1583 add_word_to_buffer(wfile, cword1, names);
1584 add_to_buffer(0, ",");
1585 add_word_to_buffer(wfile, cword2, names);
1586 add_to_buffer(0, "]");
1587 }
1588 else {
1589 add_to_buffer(0, " ");
1590 add_iword_to_buffer(wfile, cword, names);
1591 }
1592 if (stateno == 1)
1593 sprintf(kbm_buffer + stringlen(kbm_buffer), ",%d]", statelist[clength]);
1594 if (stateno == 2)
1595 sprintf(kbm_buffer + stringlen(kbm_buffer), ",%d]",
1596 fsaptr->states->setToLabels[statelist[clength]]);
1597
1598 fprintf(wfile, "%s", kbm_buffer);
1599 *kbm_buffer = '\0';
1600 }
1601 /* Now proceed to next word in the search */
1602 firste = 1;
1603 backtrack = TRUE;
1604 while (backtrack && !done) {
1605 if (clength < max) {
1606 cstate = statelist[clength];
1607 i = firste - 1;
1608 while (backtrack && ++i <= ne)
1609 if ((im = target(dense, table, i, cstate, dr)) >
1610 0) { /* found next node */
1611 cword[clength++] = i;
1612 statelist[clength] = im;
1613 backtrack = FALSE;
1614 }
1615 }
1616 if (backtrack) {
1617 if (clength == 0)
1618 done = TRUE;
1619 else {
1620 firste = cword[--clength] + 1;
1621 cword[clength] = 0;
1622 }
1623 }
1624 }
1625 }
1626
1627 if (numbers) {
1628 assert(names);
1629 for (i = 1; i <= ne; i++)
1630 tfree(names[i]);
1631 tfree(names);
1632 }
1633 tfree(fsaptr->is_accepting);
1634 tfree(cword);
1635 if (prod) {
1636 tfree(cword1);
1637 tfree(cword2);
1638 }
1639 tfree(statelist);
1640
1641 return (int)foundword;
1642 }
1643
1644 /* *fsaptr must be a two-variable fsa, in dense format. This routine
1645 * alters *fsaptr by swapping the variable. That is it replaces transitions
1646 * s - (a,b) -> t by s - (b,a) -> t, for a,b in the base-alphabet.
1647 */
fsa_swap_coords(fsa * fsaptr)1648 int fsa_swap_coords(fsa *fsaptr)
1649 {
1650 int ***dtable, ngens1, ns, g1, g2, st, st1, st2;
1651
1652 if (kbm_print_level >= 3)
1653 printf(" #Calling fsa_swap_coords.\n");
1654 if (!fsaptr->flags[DFA]) {
1655 fprintf(stderr, "Error: fsa_swap_coords only applies to DFA's.\n");
1656 return -1;
1657 }
1658
1659 if (fsaptr->alphabet->type != PRODUCT || fsaptr->alphabet->arity != 2) {
1660 fprintf(stderr, "Error in fsa_swap_coords: fsa must be 2-variable.\n");
1661 return -1;
1662 }
1663
1664 if (fsaptr->table->table_type != DENSE) {
1665 fprintf(stderr, "Error: function fsa_swap_coords must be called with a "
1666 "densely-stored fsa.\n");
1667 return -1;
1668 }
1669
1670 fsaptr->flags[BFS] = FALSE;
1671 fsa_table_dptr_init(fsaptr);
1672 ns = fsaptr->states->size;
1673 ngens1 = fsaptr->alphabet->base->size + 1;
1674 dtable = fsaptr->table->table_data_dptr;
1675
1676 for (st = 1; st <= ns; st++) {
1677 for (g1 = 1; g1 <= ngens1; g1++)
1678 for (g2 = 1; g2 < g1; g2++) {
1679 st1 = dense_dtarget(dtable, g1, g2, st);
1680 st2 = dense_dtarget(dtable, g2, g1, st);
1681 set_dense_dtarget(dtable, g1, g2, st, st2);
1682 set_dense_dtarget(dtable, g2, g1, st, st1);
1683 }
1684 }
1685 return 0;
1686 }
1687
1688 /****************************************************************
1689 * NEW FSA STUFF - by Laurent Bartholdi
1690 ****************************************************************/
1691
1692 /* fsa_mod_count() computes the number of elements of length i in the
1693 accepted language, for all 0 <= i <= n where n=#of states in fsa.
1694 All computations are mod. p
1695 */
fsa_mod_count(fsa * fsaptr,unsigned p,unsigned num)1696 unsigned *fsa_mod_count(fsa *fsaptr, unsigned p, unsigned num)
1697 {
1698 unsigned *state_count, *new_count, *count, n, dr, i, j, k;
1699 int **table;
1700 boolean dense;
1701
1702 if (!fsaptr->flags[DFA]) {
1703 fprintf(stderr, "Error: fsa_mod_count only applies to DFA's.\n");
1704 return 0;
1705 }
1706 if (!fsaptr->flags[TRIM]) {
1707 printf("#WARNING: fsa_mod_count applied to fsa not known to be trim.\n");
1708 printf("#It will be minimized before proceeding.\n");
1709 if (fsa_minimize(fsaptr) == -1)
1710 return 0;
1711 }
1712
1713 n = fsaptr->states->size;
1714 dense = fsaptr->table->table_type == DENSE;
1715 table = fsaptr->table->table_data_ptr;
1716 dr = fsaptr->table->denserows;
1717
1718 tmalloc(state_count, unsigned, n + 1); /* # of words ending at given state */
1719 tmalloc(new_count, unsigned,
1720 n + 1); /* new # of words ending at given state */
1721 tmalloc(count, unsigned, num + 1); /* the answer */
1722
1723 for (i = 1; i <= n; i++)
1724 state_count[i] = 0;
1725 for (i = 1; i <= fsaptr->num_initial; i++)
1726 state_count[fsaptr->initial[i]]++;
1727
1728 for (i = 0; i <= num; i++) {
1729 count[i] = 0;
1730 for (j = 1; j <= fsaptr->num_accepting; j++)
1731 count[i] =
1732 (count[i] +
1733 state_count[fsaptr->num_accepting == n ? j : fsaptr->accepting[j]]) %
1734 p;
1735
1736 for (j = 1; j <= n; j++)
1737 new_count[j] = 0;
1738 for (j = 1; j <= n; j++)
1739 for (k = 1; k <= fsaptr->alphabet->size; k++) {
1740 int im = target(dense, table, k, j, dr);
1741 if (im > 0)
1742 new_count[im] = (new_count[im] + state_count[j]) % p;
1743 }
1744 for (j = 1; j <= n; j++)
1745 state_count[j] = new_count[j];
1746 }
1747 tfree(state_count);
1748 tfree(new_count);
1749
1750 return count;
1751 }
1752
mod_inverse(unsigned i,unsigned p)1753 unsigned mod_inverse(unsigned i, unsigned p)
1754 {
1755 unsigned m = i, n = p;
1756 int a = 1, b = 0, c = 0, d = 1;
1757 /* we have a*i+b*p = m, c*i+d*p = n at all times;
1758 further m<n */
1759 while (m != 0) {
1760 unsigned q = n / m, tm = m;
1761 int ta = a, tb = b;
1762 m = n - q * m, a = c - q * a, b = d - q * b;
1763 n = tm, c = ta, d = tb;
1764 }
1765 if (n != 1)
1766 fprintf(stderr, "In mod_inverse(): cannot compute");
1767 return (c + p) % p;
1768 }
1769
1770 /* solve A*B=A[n] in n-dimensional matrices and vectors, mod. p.
1771 the return value is the smallest possible size of B,
1772 or -1 if the computation could not be performed. */
mod_solve(int ** A,int * B,unsigned p,unsigned n)1773 int mod_solve(int **A, int *B, unsigned p, unsigned n)
1774 {
1775 unsigned degree = n;
1776 int i, j, k;
1777
1778 for (i = 0; i < n; i++) { /* clean up the ith column */
1779 int inv, pivot = -1;
1780 for (j = i; j < n; j++)
1781 if (A[j][i] != 0) {
1782 pivot = j;
1783 break;
1784 }
1785 if (pivot < 0) { /* oops... singular matrix ? */
1786 for (j = i; j < n; j++)
1787 if (A[j][n] != 0) {
1788 fprintf(stderr, "In mod_solve(): Singular matrix\n");
1789 return -1;
1790 }
1791 degree = i;
1792 break;
1793 }
1794 if (A[i][i] == 0)
1795 for (j = i; j <= n; j++)
1796 A[i][j] = (A[i][j] + A[pivot][j]) % p;
1797 inv = mod_inverse(A[i][i], p);
1798 for (j = i; j <= n; j++)
1799 A[i][j] = (A[i][j] * inv) % p;
1800 for (j = i + 1; j < n; j++)
1801 for (k = n; k >= i; k--)
1802 A[j][k] = (A[j][k] + (p - A[j][i]) * A[i][k]) % p;
1803 }
1804
1805 for (i = degree - 1; i >= 0; i--) {
1806 B[i] = A[i][n];
1807 for (j = 0; j < i; j++) {
1808 A[j][n] = (A[j][n] + (p - A[j][i]) * A[i][n]) % p;
1809 A[j][i] = 0;
1810 }
1811 }
1812 return degree;
1813 }
1814
fsa_mod_growth(fsa * fsaptr,fraction * f,unsigned p)1815 int fsa_mod_growth(fsa *fsaptr, fraction *f, unsigned p)
1816 {
1817 unsigned *count, n, i, j;
1818 int **A;
1819
1820 n = fsaptr->states->size;
1821 tmalloc(A, int *, n);
1822 for (i = 0; i < n; i++)
1823 tmalloc(A[i], int, n + 1);
1824 tmalloc(f->num, int, n + 1);
1825 tmalloc(f->den, int, n + 1);
1826
1827 count = fsa_mod_count(fsaptr, p, 2 * n);
1828 if (count == 0)
1829 return -1;
1830 for (i = 0; i < n; i++) {
1831 for (j = 0; j < n; j++)
1832 A[i][j] = count[n + i - j];
1833 A[i][n] = (p - count[i + n + 1]) % p;
1834 }
1835 f->den[0] = 1;
1836 f->dd = mod_solve(A, f->den + 1, p, n);
1837
1838 for (i = 0; i <= n; i++)
1839 f->num[i] = 0;
1840 for (i = 0; i <= n; i++)
1841 for (j = 0; j <= f->dd && i + j <= n; j++)
1842 f->num[i + j] = (f->num[i + j] + count[i] * f->den[j]) % p;
1843 for (i = n;; i--)
1844 if (f->num[i] != 0) {
1845 f->nd = i;
1846 break;
1847 };
1848
1849 for (i = 0; i < n; i++)
1850 tfree(A[i]);
1851 tfree(A);
1852 return 0;
1853 }
1854
mod_normal(int * poly,unsigned d,unsigned p)1855 void mod_normal(int *poly, unsigned d, unsigned p)
1856 {
1857 int i;
1858 for (i = 0; i <= d; i++) {
1859 poly[i] %= p;
1860 if (poly[i] < 0)
1861 poly[i] += p;
1862 if (poly[i] > p / 2)
1863 poly[i] -= p;
1864 }
1865 }
1866
1867 /* Edited by dfh to buffer printing and insert new-lines
1868 * returns true if it prints a new line, otherwise false.
1869 */
print_poly(FILE * f,int * poly,unsigned d,char * var)1870 boolean print_poly(FILE *f, int *poly, unsigned d, char *var)
1871 {
1872 boolean first = TRUE, ans = FALSE;
1873 int i, bufflen;
1874
1875 bufflen = strlen(kbm_buffer);
1876 for (i = 0; i <= d; i++)
1877 if (poly[i] != 0) {
1878 if (first) {
1879 if (poly[i] > 0 && (i == 0 || poly[i] > 1))
1880 sprintf(kbm_buffer + strlen(kbm_buffer), "%d", poly[i]);
1881 else if (poly[i] < 0 && (i == 0 || poly[i] < -1))
1882 sprintf(kbm_buffer + strlen(kbm_buffer), "%d", poly[i]);
1883 else if (poly[i] == -1)
1884 sprintf(kbm_buffer + strlen(kbm_buffer), "-");
1885 }
1886 else {
1887 if (poly[i] > 1)
1888 sprintf(kbm_buffer + strlen(kbm_buffer), " + %d", poly[i]);
1889 else if (poly[i] < -1)
1890 sprintf(kbm_buffer + strlen(kbm_buffer), " - %d", -poly[i]);
1891 else if (poly[i] == 1)
1892 sprintf(kbm_buffer + strlen(kbm_buffer), " + ");
1893 else if (poly[i] == -1)
1894 sprintf(kbm_buffer + strlen(kbm_buffer), " - ");
1895 }
1896 if (i >= 1) {
1897 if (poly[i] == 1 || poly[i] == -1)
1898 sprintf(kbm_buffer + strlen(kbm_buffer), "%s", var);
1899 else
1900 sprintf(kbm_buffer + strlen(kbm_buffer), "*%s", var);
1901 }
1902 if (i >= 2)
1903 sprintf(kbm_buffer + strlen(kbm_buffer), "^%d", i);
1904 if (strlen(kbm_buffer) > 66 && i < d) {
1905 printbuffer(f);
1906 add_to_buffer(bufflen + 1, "");
1907 ans = TRUE;
1908 }
1909 first = FALSE;
1910 }
1911 if (first)
1912 fprintf(f, "0");
1913 return ans;
1914 }
1915
1916 /*
1917 void
1918 print_poly(FILE *f, int *poly, unsigned d, char *var)
1919 {
1920 boolean first = TRUE;
1921 int i;
1922
1923 for (i = 0; i <= d; i++)
1924 if (poly[i] != 0) {
1925 if (first) {
1926 if (poly[i] > 0) fprintf(f,"%d", poly[i]);
1927 else fprintf(f,"-%d", -poly[i]);
1928 } else {
1929 if (poly[i] > 0) fprintf(f," + %d", poly[i]);
1930 else fprintf(f," - %d", -poly[i]);
1931 }
1932 if (i >= 1) fprintf(f,"*%s", var);
1933 if (i >= 2) fprintf(f,"^%d", i);
1934
1935 first = FALSE;
1936 }
1937 if (first) fprintf(f,"0");
1938 }
1939 */
1940
fsa_growth(FILE * wfile,fsa * fsaptr,unsigned * primes,char * var)1941 int fsa_growth(FILE *wfile, fsa *fsaptr, unsigned *primes, char *var)
1942 {
1943 boolean cr;
1944 fraction f = {0,0,0,0}, newf;
1945 int i;
1946 boolean consistent = TRUE;
1947 boolean printres;
1948 boolean firstprime = TRUE;
1949
1950 while (*primes) {
1951 printres = FALSE;
1952 fprintf(wfile, "#result modulo prime %d:", *primes);
1953 if (kbm_print_level >= 2)
1954 printf(" #Computing growth modulo %d\n", *primes);
1955
1956 if (fsa_mod_growth(fsaptr, &newf, *primes) == -1)
1957 return -1;
1958 mod_normal(newf.den, newf.dd, *primes);
1959 mod_normal(newf.num, newf.nd, *primes);
1960 if (firstprime) {
1961 f = newf;
1962 printres = TRUE;
1963 fprintf(wfile, "\n");
1964 }
1965 else if (f.dd != newf.dd || f.nd != newf.nd) {
1966 tfree(f.num);
1967 tfree(f.den);
1968 f = newf;
1969 consistent = FALSE;
1970 printres = TRUE;
1971 }
1972 else {
1973 boolean fixup = FALSE;
1974 for (i = 0; i <= newf.dd; i++)
1975 if (newf.den[i] != f.den[i]) {
1976 fixup = TRUE;
1977 f.den[i] = newf.den[i];
1978 }
1979 for (i = 0; i <= newf.nd; i++)
1980 if (newf.num[i] != f.num[i]) {
1981 fixup = TRUE;
1982 f.num[i] = newf.num[i];
1983 }
1984 if (fixup) {
1985 consistent = FALSE;
1986 printres = TRUE;
1987 }
1988 tfree(newf.num);
1989 tfree(newf.den);
1990 }
1991 if (printres) {
1992 if (firstprime)
1993 firstprime = FALSE;
1994 else
1995 fprintf(wfile, "\n");
1996 sprintf(kbm_buffer + strlen(kbm_buffer), "(");
1997 cr = print_poly(wfile, f.num, f.nd, var);
1998 sprintf(kbm_buffer + strlen(kbm_buffer), ")/");
1999 if (cr || strlen(kbm_buffer) >= 40)
2000 printbuffer(wfile);
2001 sprintf(kbm_buffer + strlen(kbm_buffer), "(");
2002 cr = print_poly(wfile, f.den, f.dd, var);
2003 sprintf(kbm_buffer + strlen(kbm_buffer), ");");
2004 printbuffer(wfile);
2005 }
2006 else
2007 fprintf(wfile, " (as previous)\n");
2008 primes++;
2009 }
2010 if (kbm_print_level >= 2) {
2011 int m = 0;
2012 for (i = 0; i <= f.nd; i++)
2013 if (f.num[i] > m)
2014 m = f.num[i];
2015 else if (f.num[i] < -m)
2016 m = -f.num[i];
2017 for (i = 0; i <= f.dd; i++)
2018 if (f.den[i] > m)
2019 m = f.den[i];
2020 else if (f.den[i] < -m)
2021 m = -f.den[i];
2022 printf(" #Degrees %d/%d, Max coefficient %d\n", f.nd, f.dd, m);
2023 }
2024 tfree(f.den);
2025 tfree(f.num);
2026 return (int)consistent;
2027 }
2028