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