Edinburgh Speech Tools  2.1-release
EST_lattice.cc
Go to the documentation of this file.
1 /*************************************************************************/
2 /* */
3 /* Centre for Speech Technology Research */
4 /* University of Edinburgh, UK */
5 /* Copyright (c) 1995,1996 */
6 /* All Rights Reserved. */
7 /* */
8 /* Permission is hereby granted, free of charge, to use and distribute */
9 /* this software and its documentation without restriction, including */
10 /* without limitation the rights to use, copy, modify, merge, publish, */
11 /* distribute, sublicense, and/or sell copies of this work, and to */
12 /* permit persons to whom this work is furnished to do so, subject to */
13 /* the following conditions: */
14 /* 1. The code must retain the above copyright notice, this list of */
15 /* conditions and the following disclaimer. */
16 /* 2. Any modifications must be clearly marked as such. */
17 /* 3. Original authors' names are not deleted. */
18 /* 4. The authors' names are not used to endorse or promote products */
19 /* derived from this software without specific prior written */
20 /* permission. */
21 /* */
22 /* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */
23 /* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */
24 /* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */
25 /* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */
26 /* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */
27 /* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */
28 /* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */
29 /* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */
30 /* THIS SOFTWARE. */
31 /* */
32 /*************************************************************************/
33 /* Author : Simon King */
34 /* Date : November 1996 */
35 /*-----------------------------------------------------------------------*/
36 /* Lattice/Finite State Network */
37 /* */
38 /*=======================================================================*/
39 
40 #include "EST_lattice.h"
41 #include <fstream>
42 #include <cstdlib>
43 
44 using namespace std;
45 
47 {
48  tf=0;
49  qmap_error_margin = 0;
50  e_move_symbol_index = 0;
51 }
52 
53 
55 {
56 
57 }
58 
61 {
62  if(nodes.head() != NULL )
63  return nodes(nodes.head());
64  else{
65  cerr << "LAttice has no nodes !" << endl;
66  return NULL;
67  }
68 
69 }
70 
71 #if 0
72 bool Lattice::build_qmap(Bigram &g, float error_margin)
73 {
74 
75  // very crude VQ (not vectors though)
76  // works best on log bigrams ?
77 
78  // to do : automatically determine error_margin
79 
80  int i,j;
81  EST_Litem *l_ptr;
82  bool flag;
83 
84  // first, build a list, then transfer to array
85  Tlist<float> list_qmap;
86 
87  qmap_error_margin = error_margin;
88 
89  for (i = 0; i < g.size(); ++i){
90  for (j = 0; j < g.size(); ++j){
91 
92  flag = false;
93  for(l_ptr=list_qmap.head();l_ptr != 0; l_ptr=l_ptr->next())
94  if(fabs(list_qmap(l_ptr) - g.p(i,j)) <= error_margin){
95  flag = true;
96  break;
97  }
98 
99  if(!flag)
100  list_qmap.append(g.p(i,j));
101 
102  }
103  }
104 
105  // special zero (within error_margin) entry, if not already there
106  flag = false;
107  for(l_ptr=list_qmap.head();l_ptr != 0; l_ptr=l_ptr->next())
108  if(fabs(list_qmap(l_ptr)) <= error_margin){
109  flag = true;
110  break;
111  }
112 
113  if(!flag)
114  list_qmap.append(0);
115 
116  qsort(list_qmap);
117 
118  i=0;
119  for(l_ptr=list_qmap.head();l_ptr != 0; l_ptr=l_ptr->next())
120  i++;
121 
122  // transfer to array
123  qmap.resize(i);
124  i=0;
125  for(l_ptr=list_qmap.head();l_ptr != 0; l_ptr=l_ptr->next())
126  qmap(i++) = list_qmap(l_ptr);
127 
128  list_qmap.clear();
129 
130 
131  cerr << "Built qmap with " << i << " entries" << endl;
132 
133  return true;
134 }
135 
136 
137 bool
138 Lattice::build_nmap(Bigram &g)
139 {
140 
141 
142  int j;
143  //name_map_entry_t entry;
144  EST_Litem *l_ptr;
145 
146  // first, build a list, then transfer to array
147  Tlist<EST_String> list_nmap;
148 
149  // wordlist must not have !ENTER of !EXIT in it
150  for (j = 0; j < g.size() - 2; ++j){
151  if(g.words(j) == "!ENTER"){
152  cerr << "Wordlist contains special word !ENTER" << endl;
153  return false;
154  }
155  if(g.words(j) == "!EXIT"){
156  cerr << "Wordlist contains special word !EXIT" << endl;
157  return false;
158  }
159  }
160 
161 
162 
163 
164  // add all words
165  for (j = 0; j < g.size() - 2; ++j)
166  list_nmap.append(g.words(j));
167 
168  // special enter and exit
169  list_nmap.append("!ENTER");
170  list_nmap.append("!EXIT");
171 
172  qsort(list_nmap);
173 
174  cerr << list_nmap << endl;
175 
176  j=0;
177  for(l_ptr=list_nmap.head();l_ptr != 0; l_ptr=l_ptr->next())
178  j++;
179 
180  // transfer to array
181  nmap.resize(j);
182  j=0;
183  for(l_ptr=list_nmap.head();l_ptr != 0; l_ptr=l_ptr->next())
184  nmap(j++) = list_nmap(l_ptr);
185 
186  list_nmap.clear();
187  cerr << "Built nmap with " << j << " entries" << endl;
188 
189  return true;
190 }
191 
192 
193 bool
194 Lattice::construct_alphabet(Bigram &g)
195 {
196 
197  int i,j,enteri,exiti,aindex,qindex,nindex,count;
198  symbol_t *sym;
199  EST_Litem *a_ptr;
200  bool flag;
201 
202  if(!build_qmap(g,1.0e-02) || !build_nmap(g)) // to do : fix
203  return false;
204 
205 
206  // temporary list
207  Tlist<symbol_t*> list_alphabet;
208 
209  // alphabet consists of all occurring combinations of
210  // nmap and qmap entries
211 
212  enteri = g.size() - 2;
213  exiti = g.size() - 1;
214 
215  aindex=0;
216 
217  // order is this way for speed
218  for (j = 0; j < g.size(); ++j){
219 
220  cerr << "constructing alphabet " << (int)((float)j*100/(float)g.size()) << "% \r";
221 
222  if(j == enteri)
223  nindex = nmap_name_to_index("!ENTER");
224  else if(j == exiti)
225  nindex = nmap_name_to_index("!EXIT");
226  else
227  nindex = nmap_name_to_index(g.words(j)); // check !!
228 
229  for (i = 0; i < g.size(); ++i){
230 
231  qindex = qmap_value_to_index(g.p(i,j));
232 
233  // have we got sym already ?
234  flag=false;
235  for(a_ptr=list_alphabet.tail();a_ptr!=NULL;a_ptr=a_ptr->prev()){
236  if( (list_alphabet(a_ptr)->nmap_index == nindex) &&
237  (list_alphabet(a_ptr)->qmap_index == qindex) ){
238  flag=true;
239  break;
240  }
241 
242  // since words are added in order, stop
243  // when we get to previous word
244  if(list_alphabet(a_ptr)->nmap_index != nindex)
245  break;
246  }
247 
248 
249  if(!flag){
250  sym = new symbol_t;
251  sym->qmap_index=qindex;
252  sym->nmap_index=nindex;
253  list_alphabet.append(sym);
254  }
255  }
256  }
257 
258  // special ENTER with prob of 1 symbol
259  nindex = nmap_name_to_index("!ENTER");
260  qindex = qmap_value_to_index(0); // log prob
261  flag=false;
262  for(a_ptr=list_alphabet.tail();a_ptr!=NULL;a_ptr=a_ptr->prev())
263  if( (list_alphabet(a_ptr)->nmap_index == nindex) &&
264  (list_alphabet(a_ptr)->qmap_index == qindex) ){
265  flag=true;
266  break;
267  }
268 
269  if(!flag){
270  sym = new symbol_t;
271  sym->qmap_index=qindex;
272  sym->nmap_index=nindex;
273  list_alphabet.append(sym);
274  }
275 
276  // and special no-label label (e-move)
277  sym = new symbol_t;
278  sym->qmap_index=-1;
279  sym->nmap_index=-1;
280  list_alphabet.append(sym);
281 
282  ptr_qsort(list_alphabet);
283 
284  count=0;
285  for(a_ptr=list_alphabet.head();a_ptr != NULL; a_ptr=a_ptr->next())
286  count++;
287 
288 
289  alphabet.resize(count);
290  count=0;
291  for(a_ptr=list_alphabet.head();a_ptr != NULL; a_ptr=a_ptr->next())
292  alphabet(count++) = *(list_alphabet(a_ptr));
293 
294  // .. to do - delete syms
295  list_alphabet.clear();
296 
297  e_move_symbol_index = alphabet_index_lookup(-1,-1);
298 
299  cerr << "Alphabet has " << count << " symbols " << endl;
300 
301  return true;
302 }
303 
304 
305 bool
306 Lattice::construct(Bigram &g)
307 {
308 
309  // every word becomes a node, every non-zero transition becomes an arc
310  // eliminate any transitions into ENTER and out of EXIT
311  int i,j,k;
312  EST_Litem *n_ptr,*a_ptr;
313  Node *n;
314  Arc *a;
315  Node *from,*to;
316  int symbol;
317  // unfortunate, but fixed in Bigram class
318  int enteri = g.size() - 2;
319  int exiti = g.size() - 1;
320  int from_name,to_name;
321 
322  // single entry node, no name since no arcs in
323  // single arc out to node called "!ENTER"
324 
325  Node *enter_node = new Node;
326  enter_node->name.append(-1); // no name !
327  nodes.append(enter_node);
328 
329  // make nodes - one for every entry in nmap
330  for(i=0; i<nmap.n(); i++){
331 
332  n = new Node;
333  n->name.append(i); // index into nmap
334  nodes.append(n);
335 
336  if(nmap(i) == "!ENTER"){ // temporary hack
337 
338  symbol = alphabet_index_lookup(i,qmap_value_to_index(0)); // for log probs !!!
339  a = new Arc;
340  a->label = symbol;
341  a->to = n;
342  enter_node->arcs_out.append(a);
343 
344  }
345 
346 
347  // keep note of final node
348  if(nmap(i) == "!EXIT") // temporary hack
349  final_nodes.append(n);
350 
351  }
352 
353  // make arcs
354  k=0;
355  for (i = 0; i < g.size(); ++i){
356  cerr << "building lattice " << (int)((float)i*100/(float)g.size()) << "% \r";
357  for (j = 0; j < g.size(); ++j){
358 
359  // ignore any transitions into ENTER or out of EXIT
360  //if((g.p(i, j) > 0) && - for probs only, can't do for log probs
361  if((j != enteri) && (i != exiti)){
362 
363  // find from and to nodes
364  from=NULL;
365  to=NULL;
366 
367  if(i == enteri)
368  from_name = nmap_name_to_index("!ENTER");
369  else
370  from_name = nmap_name_to_index(g.words(i));
371 
372  if(j == exiti)
373  to_name = nmap_name_to_index("!EXIT");
374  else
375  to_name= nmap_name_to_index(g.words(j));
376 
377  for (n_ptr = nodes.head(); n_ptr != 0; n_ptr = n_ptr->next()){
378  int name = nodes(n_ptr)->name(nodes(n_ptr)->name.head());
379  if(name == from_name)
380  from = nodes(n_ptr);
381  if(name == to_name)
382  to = nodes(n_ptr);
383  }
384 
385  if(from==NULL){
386  cerr << "Couldn't find 'from' node " << nmap_index_to_name(from_name) << endl;
387  return false;
388  }
389 
390  if(to==NULL){
391  cerr << "Couldn't find 'to' node " << nmap_index_to_name(to_name) << endl;
392  return false;
393  }
394 
395  // get arc symbol - speed up this fn !
396  symbol = alphabet_index_lookup(to_name,qmap_value_to_index(g.p(i,j)));
397  if(symbol < 0){
398  cerr << "Couldn't lookup symbol in alphabet !" << endl;
399  return false;
400  }
401 
402  a = new Arc;
403  a->label = symbol;
404  a->to = to;
405 
406  from->arcs_out.append(a);
407 
408 
409  }
410  }
411  }
412  cerr << " \r";
413 
414  int c1=0,c2=0,c3=0;
415  for(n_ptr=nodes.head();n_ptr!=NULL;n_ptr=n_ptr->next()){
416  c1++;
417  for(a_ptr=nodes(n_ptr)->arcs_out.head();a_ptr!=NULL; a_ptr=a_ptr->next())
418  c2++;
419  }
420 
421  for (n_ptr = final_nodes.head(); n_ptr != 0; n_ptr = n_ptr->next())
422  c3++;
423 
424  cerr << "NFA has " << c1
425  << " nodes (" << c3 << " final)"
426  << " and " << c2 << " arcs" << endl;
427 
428  return true;
429 }
430 #endif
431 
433 {
434  // very simple, but potentially time/memory consuming
435 
436  // make a new lattice whose nodes are all permutations
437  // of the nodes in the old lattice
438  // BUT : only make the nodes which are actually required
439  // (otherwise number of new nodes = 2^(number of old nodes)
440 
441  // we will call the old lattice NFA and the new one DFA
442 
443  EST_Litem *n_ptr,*n2_ptr,*a_ptr,*l_ptr;
444  Node *new_node;
445  EST_TList<Node*> new_nodes;
446  EST_TList<Node*> new_final_nodes;
447  EST_TList<Arc*> new_arcs;
448  EST_TList<Arc*> arc_list;
449  EST_TList<int> new_name;
450  int c,count,current_label,new_arcs_made;
451  bool is_final;
452 
453  // first, sort nodes' lists of arcs by label to make
454  // it easier
455  cerr << "sorting arc lists" << endl;
456  sort_arc_lists();
457 
458  cerr << "making new nodes" << endl;
459 
460  // - for every node in the NFA, look at the outgoing arcs with
461  // the same label
462  // - make a DFA node which is a combination of the NFA nodes
463  // which are the destinations of those arcs
464 
465  // there are more DFA nodes made later
466 
467  // enter node is special case, it has no in-going arcs
468  // so will not be made in the following loop
469 
470  // for now, assume one enter node at head of list ... hmmmmm
471  new_node = new Node;
472  if(new_node == NULL){
473  cerr << "Could not allocate any more memory";
474  return false;
475  }
476  new_node->name = nodes(nodes.head())->name;
477  new_nodes.append(new_node);
478 
479 
480 
481  for (n_ptr = nodes.head(); n_ptr != 0; n_ptr = n_ptr->next()){
482 
483  for (a_ptr = nodes(n_ptr)->arcs_out.head(); a_ptr != 0; a_ptr = a_ptr->next()){
484 
485  current_label = nodes(n_ptr)->arcs_out(a_ptr)->label;
486 
487  // make list of arc destinations along arcs with this label
488  is_final=false;
489  new_name.clear();
490  new_name = nodes(n_ptr)->arcs_out(a_ptr)->to->name;
491  if(final(nodes(n_ptr)->arcs_out(a_ptr)->to) )
492  is_final=true;
493  while((a_ptr != NULL) &&
494  (a_ptr->next() != NULL) &&
495  (nodes(n_ptr)->arcs_out(a_ptr->next())->label == current_label)){
496  merge_sort_unique(new_name,nodes(n_ptr)->arcs_out(a_ptr->next())->to->name);
497 
498  if( !is_final && final(nodes(n_ptr)->arcs_out(a_ptr->next())->to) )
499  is_final=true;
500 
501  a_ptr=a_ptr->next();
502 
503  }
504 
505  // make new node with this name, unless we already have one
506  bool flag=false;
507  for (n2_ptr = new_nodes.head(); n2_ptr != 0; n2_ptr = n2_ptr->next())
508  if( new_nodes(n2_ptr)->name == new_name ){
509  flag=true;
510  break;
511  }
512 
513  if(!flag){ // need to make new node
514 
515  new_node = new Node;
516  if(new_node == NULL){
517  cerr << "Could not allocate any more memory";
518  count=0;
519  for (n2_ptr = new_nodes.head(); n2_ptr != 0; n2_ptr = n2_ptr->next())
520  count++;
521  cerr << " after making " << count << " nodes" << endl;
522  return false;
523  }
524 
525  new_node->name = new_name;
526  new_nodes.append(new_node);
527 
528  if(is_final)
529  new_final_nodes.append(new_node);
530  }
531 
532  } // loop round outgoing arcs for this node
533 
534  } // loop round NFA nodes
535 
536 
537  // now, for every node in the DFA, its 'transition function' (i.e. outgoing arcs)
538  // is the sum of the transition functions of its constituent nodes from
539  // the NFA
540 
541  c=0;
542  new_arcs_made=0;
543  for (n_ptr = new_nodes.head(); n_ptr != 0; n_ptr = n_ptr->next()){
544 
545  c++;
546  cerr << "Processing node " << c
547  << " arcs=" << new_arcs_made << " \r";
548 
549  // find constituent nodes in NFA (only works if NFA names are single ints !)
550  arc_list.clear();
551  for(l_ptr=new_nodes(n_ptr)->name.head(); l_ptr != 0; l_ptr = l_ptr->next()){
552 
553  for(n2_ptr = nodes.head(); n2_ptr != 0; n2_ptr = n2_ptr->next()){
554 
555  if(nodes(n2_ptr)->name(nodes(n2_ptr)->name.head()) ==
556  new_nodes(n_ptr)->name(l_ptr))
557  arc_list += nodes(n2_ptr)->arcs_out;
558 
559 
560  }
561  }
562 
563  // now we have a list of all the NFA nodes we can 'get to'
564  // from this DFA node, sort by label and find the
565  // DFA node for each label
566 
567  // or rather, take the arc list from above, and collapse
568  // all arcs with the same label into one arc to the DFA
569  // node which is the equivalent of the NFA nodes at the
570  // end of those arcs
571 
572  sort_by_label(arc_list);
573 
574  for(a_ptr=arc_list.head();a_ptr!=NULL;a_ptr=a_ptr->next()){
575 
576  current_label=arc_list(a_ptr)->label;
577  //cerr << " label " << current_label;
578 
579  is_final=false;
580  EST_TList<int> new_name2;
581  new_name2 = arc_list(a_ptr)->to->name;
582  if(final(arc_list(a_ptr)->to) )
583  is_final=true;
584  while((a_ptr != NULL) &&
585  (a_ptr->next() != NULL) &&
586  (arc_list(a_ptr->next())->label == current_label)){
587  merge_sort_unique(new_name2,arc_list(a_ptr)->to->name);
588  if( !is_final && final(arc_list(a_ptr)->to) )
589  is_final=true;
590  a_ptr=a_ptr->next();
591  }
592 
593  //cerr << " -> " << new_name2;
594 
595  // find DFA node with that name
596  bool flag=false;
597  for (n2_ptr = new_nodes.head(); n2_ptr != 0; n2_ptr = n2_ptr->next())
598  if( new_nodes(n2_ptr)->name == new_name2 ){
599  flag=true;
600  break;
601  }
602 
603  if(!flag){ // failed to make node previously, do it now
604  new_node = new Node;
605  if(new_node == NULL){
606  cerr << "Could not allocate any more memory";
607  count=0;
608  for (n2_ptr = new_nodes.head(); n2_ptr != 0; n2_ptr = n2_ptr->next())
609  count++;
610  cerr << " after making " << count << " nodes" << endl;
611  return false;
612  }
613 
614  new_node->name = new_name2;
615  new_nodes.append(new_node);
616  link(new_nodes(n_ptr),new_node,current_label);
617 
618  if(is_final)
619  new_final_nodes.append(new_node);
620 
621  }else{
622 
623  link(new_nodes(n_ptr),new_nodes(n2_ptr),current_label);
624 
625  }
626 
627  new_arcs_made++;
628  }
629 
630 
631  } // loop round DFA nodes
632 
633  cerr << endl;
634 
635  // delete old nodes, and replace with new nodes
636  for (n_ptr = nodes.head(); n_ptr != 0; n_ptr = n_ptr->next())
637  delete nodes(n_ptr);
638  nodes.clear();
639  nodes=new_nodes;
640  new_nodes.clear();
641 
642  final_nodes.clear();
643  final_nodes=new_final_nodes;
644  new_final_nodes.clear();
645 
646  int c1=0,c2=0,c3=0;
647  for(n_ptr=nodes.head();n_ptr!=NULL;n_ptr=n_ptr->next()){
648  c1++;
649  for(a_ptr=nodes(n_ptr)->arcs_out.head();a_ptr!=NULL; a_ptr=a_ptr->next())
650  c2++;
651  }
652 
653  for (n_ptr = final_nodes.head(); n_ptr != 0; n_ptr = n_ptr->next())
654  c3++;
655 
656  cerr << "DFA has " << c1
657  << " nodes (" << c3 << " final)"
658  << " and " << c2 << " arcs" << endl;
659 
660 
661  return true;
662 }
663 
664 bool
665 Lattice::link(Node *n1, Node *n2, int label)
666 {
667 
668  //if(l==NULL)
669  //l=&arcs;
670 
671  // create arc between two nodes
672  // in direction n1,n2
673  Arc *new_arc;
674 
675  if( (n1==NULL) || (n2==NULL) ){
676  cerr << "Can't link null nodes" << endl;
677  return false;
678  }
679 
680 
681 
682  new_arc = new Arc;
683  //new_arc->from = n1;
684  new_arc->to = n2;
685  new_arc->label = label;
686 
687  n1->arcs_out.append(new_arc);
688  //n2->arcs_in.append(new_arc);
689  //l->append(new_arc);
690 
691  return true;
692 }
693 
694 void
696 {
697  EST_Litem *n_ptr;
698 
699  for (n_ptr = nodes.head(); n_ptr != 0; n_ptr = n_ptr->next()){
700 
701  // can't sort nodes(n_ptr)->arcs_out directly
702  // since it is a list of pointers
703 
704  sort_by_label(nodes(n_ptr)->arcs_out);
705 
706  }
707 
708 }
709 
710 void
712  ptr_qsort(l);
713 }
714 
715 
716 bool
718 {
719 
720  int i,j;
721  EST_Litem *n_ptr,*n2_ptr;
722 
723  int num_nodes = nodes.length();
724  // not every element will be used
725  dst = new bool*[num_nodes];
726  if(dst==NULL){
727  cerr << "Not enough memory" << endl;
728  return false;
729  }
730  for(i=0;i<num_nodes;i++){
731  dst[i] = new bool[num_nodes];
732  if(dst[i]==NULL){
733  cerr << "Not enough memory" << endl;
734  return false;
735  }
736  for(j=0;j<num_nodes;j++)
737  dst[i][j] = false;
738 
739  }
740 
741  cerr << "final/non-final scan";
742  // any final/non-final (or non-final/final) pairs are distinguished immediately
743  for(i=0,n_ptr=nodes.head();n_ptr->next()!=NULL;n_ptr=n_ptr->next(),i++){
744  for(j=i+1,n2_ptr=n_ptr->next();n2_ptr!=NULL;n2_ptr=n2_ptr->next(),j++){
745 
746  if(final(nodes(n_ptr)) && !final(nodes(n2_ptr)))
747  dst[i][j] = true;
748  else if(!final(nodes(n_ptr)) && final(nodes(n2_ptr)))
749  dst[i][j] = true;
750 
751  }
752  }
753  cerr << "\r \r";
754 
755  // two possible methods, depending on network representation
756  // for sparse networks, use actual nodes and their lists of arcs
757  //build_distinguished_state_table_direct(dst);
758 
759  // for dense networks, use a transition function matrix
760  // which will be faster but more memory consuming
761 
762  if(!build_transition_function()){
763  cerr << "Couldn't build transition function" << endl;
764  return false;
765  }
766 
767  if(!build_distinguished_state_table_from_transition_function(dst)){
768  cerr << "Couldn't build dst from transition function" << endl;
769  return false;
770  }
771 
772  // delete tf, since it will be wrong for minimised net
773  for(i=0;i<num_nodes;i++)
774  delete [] tf[i];
775  delete [] tf;
776  tf=NULL;
777 
778  return true;
779 }
780 
781 bool
783 {
784 
785  int i,j,i1,j1,scan_count,this_symbol;
786  EST_Litem *n_ptr,*n2_ptr,*a_ptr,*s_ptr;
787  bool flag,flag2;
788 
789  // carry out repeated scans of the distinguished state table until no more
790  // cells are set true
791 
792  flag=true;
793  scan_count=0;
794  while(flag){
795  flag=false;
796 
797  scan_count++;
798 
799  for(i=0,n_ptr=nodes.head();n_ptr->next()!=NULL;n_ptr=n_ptr->next(),i++){
800 
801  for(j=i+1,n2_ptr=n_ptr->next();n2_ptr!=NULL;n2_ptr=n2_ptr->next(),j++){
802 
803  cerr << "scan " << scan_count << " : " << i << "," << j << " \r";
804 
805  if(!dst[i][j]){
806 
807  // go through alphabet, or rather just those symbols
808  // occurring on the arcs out of this pair of nodes
809 
810  flag2=true;
811  s_ptr=nodes(n_ptr)->arcs_out.head();
812  while(s_ptr != NULL){
813 
814 
815  if(flag2){ // we are going through symbols on arcs out of 'nodes(n_ptr)'
816  this_symbol=nodes(n_ptr)->arcs_out(s_ptr)->label;
817  i1 = node_index(nodes(n_ptr)->arcs_out(s_ptr)->to);
818 
819  j1=-1;
820  for(a_ptr=nodes(n2_ptr)->arcs_out.head();
821  a_ptr!=NULL; a_ptr=a_ptr->next())
822  if(nodes(n2_ptr)->arcs_out(a_ptr)->label == this_symbol)
823  j1 = node_index(nodes(n2_ptr)->arcs_out(a_ptr)->to);
824 
825  }else{ // we are going through symbols on arcs out of 'nodes(n2_ptr)'
826  this_symbol=nodes(n2_ptr)->arcs_out(s_ptr)->label;
827  j1 = node_index(nodes(n2_ptr)->arcs_out(s_ptr)->to);
828 
829  i1=-1;
830  for(a_ptr=nodes(n_ptr)->arcs_out.head();
831  a_ptr!=NULL; a_ptr=a_ptr->next())
832  if(nodes(n_ptr)->arcs_out(a_ptr)->label == this_symbol)
833  i1 = node_index(nodes(n_ptr)->arcs_out(a_ptr)->to);
834  }
835 
836 
837  // States (nodes) are distinguished if, for any symbol, they
838  // have transitions (arcs) to a pair of distinguished states.
839  // This includes the case where, for any symbol, one state
840  // has a transition and the other does not
841 
842  if( ( (i1>=0) && (j1>=0) && dst[i1][j1]) ||
843  ( (i1>=0) && (j1<0) ) ||
844  ( (j1>=0) && (i1<0) ) )
845  {
846  dst[i][j] = true;
847  flag=true;
848  break; // out of s_ptr loop
849 
850  }
851 
852  s_ptr=s_ptr->next();
853  if( (s_ptr==NULL) && (flag2) ){ // now go down second list
854  s_ptr=nodes(n2_ptr)->arcs_out.head();
855  flag2=false;
856  }
857 
858  }
859  }
860  }
861  }
862  }
863 
864  return true;
865 }
866 
867 bool
869 {
870  int i,j,i2,j2,k,scan_count;
871  int num_nodes = nodes.length();
872  int num_symbols = alphabet.n();
873  bool flag;
874 
875  flag=true;
876  scan_count=0;
877  while(flag){
878  flag=false;
879 
880  scan_count++;
881 
882  for(i=0;i<num_nodes-1;i++){
883 
884  cerr << "scan " << scan_count << " : row "
885  << i << " \r";
886 
887  for(j=i+1;j<num_nodes;j++){
888 
889  if( !dst[i][j] ){
890 
891  for(k=0;k<num_symbols;k++){
892 
893  i2 = tf[i][k];
894  j2 = tf[j][k];
895 
896  if((i2<0) && (j2>=0)){
897  dst[i][j] = true;
898  flag=true;
899  break;
900 
901  }else if((j2<0) && (i2>=0)){
902  dst[i][j] = true;
903  flag=true;
904  break;
905 
906  }else if( (i2>0) && (j2>0) && dst[i2][j2] ){
907  dst[i][j] = true;
908  flag=true;
909  break;
910  }
911 
912  }
913  }
914  }
915  }
916  }
917 
918  return true;
919 }
920 
921 bool
923 {
924 
925  // method, make distinguished state table
926  // scan all pairs of states (a.k.a. nodes)
927 
928 
929  int i,j;
930  EST_Litem *n_ptr,*n2_ptr,*n3_ptr,*a_ptr;
931  int num_nodes = nodes.length();
932  bool **dst = NULL; // distinguished state table
933  bool flag;
934 
935  if(!build_distinguished_state_table(dst)){
936  cerr << "Couldn't build distinguished state table" << endl;
937  delete[] dst;
938  return false;
939  }
940 
941  int count=0,count2=0;
942  for(i=0;i<num_nodes-1;i++)
943  for(j=i+1;j<num_nodes;j++)
944  if(!dst[i][j])
945  count++;
946  else
947  count2++;
948 
949  cerr << "There are " << count << " undistinguished pairs of nodes and "
950  << count2 << " distinguished pairs" << endl;
951 
952 
953  // make lists of nodes to be merged
954  EST_TList<Node *> merge_list;
955 
956 
957 
958  flag=true;
959  while(flag){
960  flag=false;
961 
962  merge_list.clear();
963  for(i=0,n_ptr=nodes.head();n_ptr->next()!=NULL;n_ptr=n_ptr->next(),i++){
964 
965  cerr << "merge, processing row " << i << " \r";
966 
967  for(j=i+1,n2_ptr=n_ptr->next();n2_ptr!=NULL;n2_ptr=n2_ptr->next(),j++){
968 
969  if(!dst[i][j]){
970 
971  // is the merge list empty ?
972  if(merge_list.head() == NULL){
973  // put this pair of nodes on merge list
974  merge_list.append(nodes(n_ptr));
975  merge_list.append(nodes(n2_ptr));
976  dst[i][j] = true;
977 
978  }else{ // merge list already has some items on it
979 
980  // see if either of this pair of nodes is on the merge list,
981  // and if so add the other node in the pair
982  bool add1=false,add2=false;
983  for(n3_ptr=merge_list.head();n3_ptr!=NULL;n3_ptr=n3_ptr->next()){
984  if(merge_list(n3_ptr) == nodes(n_ptr))
985  add2=true;
986  if(merge_list(n3_ptr) == nodes(n2_ptr))
987  add1=true;
988  }
989 
990 
991  if(add1 && !add2){
992  merge_list.append(nodes(n_ptr));
993  dst[i][j] = true;
994  }else if(add2 && !add1){
995  merge_list.append(nodes(n2_ptr));
996  dst[i][j] = true;
997  }
998 
999 
1000  }
1001  }
1002  }
1003  }
1004 
1005  // anything on the merge list ?
1006  if(merge_list.head() != NULL){
1007 
1008  // so merge them
1009  count=0;
1010  for(n_ptr=merge_list.head();n_ptr!=NULL;n_ptr=n_ptr->next())
1011  count++;
1012  cerr << "merging " << count << " nodes out of ";
1013 
1014  count=0;
1015  for(n_ptr=nodes.head();n_ptr!=NULL;n_ptr=n_ptr->next())
1016  count++;
1017  cerr << count;
1018 
1019  merge_nodes(merge_list);
1020  flag=true;
1021 
1022  count=0;
1023  for(n_ptr=nodes.head();n_ptr!=NULL;n_ptr=n_ptr->next())
1024  count++;
1025  cerr << " leaving " << count << endl;
1026 
1027 
1028  }
1029 
1030 
1031  }
1032 
1033  int c1=0,c2=0;
1034  for(n_ptr=nodes.head();n_ptr!=NULL;n_ptr=n_ptr->next()){
1035  c1++;
1036  for(a_ptr=nodes(n_ptr)->arcs_out.head();a_ptr!=NULL; a_ptr=a_ptr->next())
1037  c2++;
1038  }
1039 
1040  cerr << "Minimum state DFA has " << c1
1041  << " nodes and " << c2 << " arcs " << endl;
1042 
1043  merge_arcs();
1044 
1045  c1=0,c2=0;
1046  for(n_ptr=nodes.head();n_ptr!=NULL;n_ptr=n_ptr->next()){
1047  c1++;
1048  for(a_ptr=nodes(n_ptr)->arcs_out.head();a_ptr!=NULL; a_ptr=a_ptr->next())
1049  c2++;
1050  }
1051 
1052  cerr << "Pruned minimum state DFA has " << c1
1053  << " nodes and " << c2 << " arcs" << endl;
1054 
1055  for(i=0;i<num_nodes;i++)
1056  delete [] dst[i];
1057  delete [] dst;
1058 
1059  return true;
1060 }
1061 
1062 
1063 void
1065 {
1066 
1067  if(l.head() == NULL)
1068  return;
1069 
1070  // make a new node with all node labels of old nodes
1071  // and all arcs of old nodes
1072 
1073  EST_Litem *n_ptr,*n2_ptr,*a_ptr,*a2_ptr;
1074  Node *new_node;
1075  new_node = new Node;
1076 
1077 
1078  // to do .. deal with final_nodes list too ....
1079 
1080 
1081 
1082  for(n_ptr=l.head();n_ptr!=NULL;n_ptr=n_ptr->next()){
1083 
1084  // get arcs
1085  for(a_ptr=l(n_ptr)->arcs_out.head();a_ptr!=NULL;a_ptr=a_ptr->next())
1086  new_node->arcs_out.append(l(n_ptr)->arcs_out(a_ptr));
1087 
1088  // get name
1089  merge_sort_unique(new_node->name,l(n_ptr)->name);
1090 
1091  // find arcs into old nodes and make them go into new node
1092  for(n2_ptr=nodes.head();n2_ptr!=NULL;n2_ptr=n2_ptr->next()){
1093  for(a2_ptr=nodes(n2_ptr)->arcs_out.head();a2_ptr!=NULL;a2_ptr=a2_ptr->next()){
1094  if(nodes(n2_ptr)->arcs_out(a2_ptr)->to == l(n_ptr))
1095  nodes(n2_ptr)->arcs_out(a2_ptr)->to = new_node;
1096  }
1097  }
1098 
1099  }
1100 
1101 
1102  // delete old nodes, but not arcs
1103  for(n_ptr=l.head();n_ptr!=NULL;n_ptr=n_ptr->next()){
1104  for(n2_ptr=nodes.head();n2_ptr!=NULL;n2_ptr=n2_ptr->next())
1105  if(nodes(n2_ptr) == l(n_ptr)){
1106  nodes(n2_ptr)->name.clear();
1107  nodes(n2_ptr)->arcs_out.clear();
1108  delete nodes(n2_ptr);
1109  nodes.remove(n2_ptr);
1110  }
1111  }
1112 
1113  nodes.append(new_node);
1114 
1115 }
1116 
1117 void
1119 {
1120 
1121  EST_Litem *n_ptr,*a_ptr,*a2_ptr;
1122  EST_TList<Arc*> merge_list;
1123  int count=0,count2;
1124 
1125  // find repeated arcs with the same label between two nodes
1126  for(n_ptr=nodes.head();n_ptr!=NULL;n_ptr=n_ptr->next()){
1127 
1128  count2=0;
1129  for(a_ptr=nodes(n_ptr)->arcs_out.head();a_ptr!=NULL; a_ptr=a_ptr->next())
1130  count2++;
1131 
1132  cerr << "merging arcs from node " << ++count
1133  << ", before:" << count2;
1134 
1135  for(a_ptr=nodes(n_ptr)->arcs_out.head();a_ptr->next()!=NULL; a_ptr=a_ptr->next()){
1136 
1137  merge_list.clear();
1138  for(a2_ptr=a_ptr->next();a2_ptr!=NULL; a2_ptr=a2_ptr->next())
1139 
1140  if((nodes(n_ptr)->arcs_out(a_ptr)->label ==
1141  nodes(n_ptr)->arcs_out(a2_ptr)->label) &&
1142 
1143  (nodes(n_ptr)->arcs_out(a_ptr)->to ==
1144  nodes(n_ptr)->arcs_out(a2_ptr)->to) ){
1145 
1146  delete nodes(n_ptr)->arcs_out(a2_ptr);
1147  a2_ptr=nodes(n_ptr)->arcs_out.remove(a2_ptr);
1148 
1149  }
1150 
1151  }
1152 
1153  count2=0;
1154  for(a_ptr=nodes(n_ptr)->arcs_out.head();a_ptr!=NULL; a_ptr=a_ptr->next())
1155  count2++;
1156 
1157  cerr<< ", after:" << count2 << endl;
1158 
1159  }
1160 
1161  cerr << " \r" << endl;
1162 
1163 }
1164 
1165 
1166 void
1168 {
1169 
1170  int count=0;
1171  EST_Litem *a_ptr;
1172  for(a_ptr=arcs.head(); a_ptr != 0; a_ptr=a_ptr->next() ){
1173  prune_arc(node, arcs(a_ptr));
1174  count++;
1175  }
1176  //cerr << "pruned " << count << " arcs" << endl;
1177 }
1178 
1179 
1180 void
1182 {
1183  remove_arc_from_nodes_out_list(node,arc);
1184  delete arc;
1185 }
1186 
1187 /*
1188 void
1189 Lattice::remove_arc_from_nodes_in_list(Node *n, Arc *a)
1190 {
1191  EST_Litem *a_ptr;
1192  for (a_ptr = n->arcs_in.head(); a_ptr != 0; a_ptr = a_ptr->next())
1193  if(n->arcs_in(a_ptr) == a)
1194  n->arcs_in.remove(a_ptr);
1195 }
1196 */
1197 
1198 void
1200 {
1201  EST_Litem *a_ptr;
1202  for (a_ptr = n->arcs_out.head(); a_ptr != 0; a_ptr = a_ptr->next())
1203  if(n->arcs_out(a_ptr) == a)
1204  n->arcs_out.remove(a_ptr);
1205 }
1206 
1207 /* not used
1208 bool
1209 Lattice::is_enter_node(Node *n)
1210 {
1211  // contains "!ENTER" in its list of names
1212  EST_Litem *l_ptr;
1213  for(l_ptr=n->name.head(); l_ptr != 0; l_ptr=l_ptr->next())
1214  if(n->name(l_ptr) == nmap_name_to_index("!ENTER")) // temporary !!
1215  return true;
1216  return false;
1217 }
1218 */
1219 
1220 /* Superseded now we have list of final nodes
1221 bool
1222 Lattice::is_exit_node(Node *n)
1223 {
1224  EST_Litem *l_ptr;
1225  for(l_ptr=n->name.head(); l_ptr != 0; l_ptr=l_ptr->next())
1226  if(n->name(l_ptr) == nmap_name_to_index("!EXIT")) // temporary !!
1227  return true;
1228  return false;
1229 }
1230 */
1231 
1232 EST_String
1234 {
1235  if(index < nmap.n())
1236  return nmap(index);
1237  else{
1238  cerr << "Warning : nmap index " << index << " out of range" << endl;
1239  return EST_String("!error!");
1240  }
1241 
1242 }
1243 
1244 int
1246 {
1247  int i,j,mid;
1248 
1249  // binary search
1250  i=0;
1251  j=nmap.n()-1;
1252 
1253  while(true){
1254 
1255  mid = (i+j)/2;
1256 
1257  if(name > nmap(mid))
1258  i = mid;
1259 
1260  else if(name < nmap(mid))
1261  j = mid;
1262 
1263  else{ // name == nmap(mid)
1264  return mid; // lucky strike
1265  }
1266 
1267  if(i==j){
1268  if(name == nmap(i))
1269  return i;
1270  else{
1271  cerr << "Lattice::nmap_name_to_index failed for '"
1272  << name << "'" << endl;
1273  return -1;
1274  }
1275 
1276  }else if(j==i+1){
1277 
1278  if(name == nmap(i))
1279  return i;
1280  else if(name == nmap(j))
1281  return j;
1282  else{
1283  cerr << "Lattice::nmap_name_to_index failed for '"
1284  << name << "'" << endl;
1285  return -1;
1286  }
1287 
1288  }
1289 
1290  }
1291 
1292  return -1;
1293 }
1294 
1295 
1296 float
1298 {
1299  if(index < qmap.n())
1300  return qmap(index);
1301  else{
1302  cerr << "Warning : qmap index " << index << " out of range" << endl;
1303  return 1;
1304  }
1305 }
1306 
1307 
1308 int
1310 {
1311  int i,j,mid;
1312 
1313  // binary search
1314  i=0;
1315  j=qmap.n()-1;
1316 
1317  while(true){
1318 
1319  mid = (i+j)/2;
1320 
1321  if(value > qmap(mid))
1322  i = mid;
1323 
1324  else if(value < qmap(mid))
1325  j = mid;
1326 
1327  else
1328  return mid; // lucky strike
1329 
1330  if(i==j)
1331  return i;
1332 
1333  else if(j==i+1){
1334 
1335  if( fabs(qmap(i) - value) < fabs(qmap(j) - value) )
1336  return i;
1337  else
1338  return j;
1339  }
1340 
1341  }
1342  return 0;
1343 }
1344 
1345 int
1347 {
1348  EST_Litem *n_ptr;
1349  for (n_ptr = nodes.head(); n_ptr != 0; n_ptr = n_ptr->next()){
1350  if(nodes(n_ptr) == n)
1351  return nodes.index(n_ptr);
1352 
1353  }
1354 
1355  //cerr << "Lattice::node_index(Node *n) couldn't find index of node " << n->name;
1356 
1357  return -1;
1358 }
1359 
1360 
1361 
1362 
1363 bool
1365 {
1366 
1367  // keep HTK happy - it can't handle multiple arcs into a node
1368  // with different word labels
1369 
1370 
1371  EST_Litem *n_ptr,*n2_ptr,*a_ptr,*w_ptr;
1372  int word;
1373  EST_TList<int> word_list;
1374  Node *new_node;
1375  Arc *new_arc;
1376  for (n_ptr = nodes.head(); n_ptr != 0; n_ptr = n_ptr->next()){
1377 
1378  // find all arcs into this node
1379  word_list.clear();
1380  for (n2_ptr = nodes.head(); n2_ptr != 0; n2_ptr = n2_ptr->next()){
1381 
1382  for (a_ptr = nodes(n2_ptr)->arcs_out.head(); a_ptr != 0; a_ptr = a_ptr->next())
1383  if(nodes(n2_ptr)->arcs_out(a_ptr)->to == nodes(n_ptr)){
1384 
1385  if(nodes(n2_ptr)->arcs_out(a_ptr)->label != e_move_symbol_index){
1386  word = alphabet_index_to_symbol(nodes(n2_ptr)->arcs_out(a_ptr)->label)->nmap_index;
1387  word_list.append(word);
1388  sort_unique(word_list);
1389 
1390  }
1391  }
1392  }
1393 
1394 
1395  // if word_list.head() is NULL we should be worried
1396  if((word_list.head() != NULL) && word_list.head()->next() != NULL){
1397 
1398  // for each word make a null node, change all offending arcs to point
1399  // to it, and make another link from null node to nodes(n_ptr)
1400 
1401  for(w_ptr=word_list.head();w_ptr!=NULL;w_ptr=w_ptr->next()){
1402 
1403  // make null node
1404  new_node = new Node;
1405  new_arc = new Arc;
1406  new_arc->label = e_move_symbol_index; // no label
1407  new_arc->to = nodes(n_ptr);
1408  new_node->arcs_out.append(new_arc);
1409 
1410  // for every arc into nodes(n_ptr) with this word label, change its arcs
1411  for (n2_ptr = nodes.head(); n2_ptr != 0; n2_ptr = n2_ptr->next()){
1412 
1413  for (a_ptr = nodes(n2_ptr)->arcs_out.head(); a_ptr != 0; a_ptr = a_ptr->next()){
1414  if(nodes(n2_ptr)->arcs_out(a_ptr)->to == nodes(n_ptr)){
1415 
1416  word = alphabet_index_to_symbol(nodes(n2_ptr)->arcs_out(a_ptr)->label)->nmap_index;
1417  if(word == word_list(w_ptr)){
1418 
1419  // change the arc
1420  nodes(n2_ptr)->arcs_out(a_ptr)->to = new_node;
1421  }
1422 
1423  }
1424  }
1425  }
1426  nodes.append(new_node);
1427  }
1428  }
1429  }
1430 
1431  // need to make sure ENTER node has no arcs in - if so add a dummy ENTER node
1432  /*
1433  //Node *enter_node = nodes(nodes.head());
1434  bool flag=false;
1435  for(n_ptr=nodes.head();n_ptr!=NULL;n_ptr=n_ptr->next()){
1436  for(a_ptr=nodes(n_ptr)->arcs_out.head();a_ptr!=NULL; a_ptr=a_ptr->next()){
1437  flag=true;
1438  break;
1439  }
1440  }
1441 
1442 
1443  if(flag){
1444  cerr << " fixing ENTER node" << endl;
1445  new_node = new Node;
1446  new_arc = new Arc;
1447  new_arc->label = enter_node->label;
1448  new_arc->to = enter_node;
1449  new_node->arcs_out.append(new_arc);
1450  nodes.append(new_node);
1451  }
1452  */
1453 
1454  // also need to make sure there is only one EXIT node
1455  if(final_nodes.length() > 1){
1456  cerr << " making single EXIT node" << endl;
1457 
1458  // make null node
1459  new_node = new Node;
1460 
1461  for(n_ptr=final_nodes.head();n_ptr!=NULL;n_ptr=n_ptr->next()){
1462 
1463  new_arc = new Arc;
1464  new_arc->label = e_move_symbol_index; // no label
1465  new_arc->to = final_nodes(n_ptr);
1466  final_nodes(n_ptr)->arcs_out.append(new_arc);
1467 
1468 
1469  }
1470 
1471  // empty final node list (nodes themselves remain on nodes list)
1472  final_nodes.clear();
1473 
1474  // now a single final node
1475  nodes.append(new_node);
1476  final_nodes.append(new_node);
1477  }
1478 
1479 
1480  int c1=0,c2=0;
1481  for(n_ptr=nodes.head();n_ptr!=NULL;n_ptr=n_ptr->next()){
1482  c1++;
1483  for(a_ptr=nodes(n_ptr)->arcs_out.head();a_ptr!=NULL; a_ptr=a_ptr->next())
1484  c2++;
1485  }
1486 
1487  cerr << "HTKified DFA has " << c1
1488  << " nodes and " << c2 << " arcs" << endl;
1489 
1490  return true;
1491 }
1492 
1493 bool
1495 {
1496  EST_Litem *n_ptr;
1497  for (n_ptr = final_nodes.head(); n_ptr != 0; n_ptr = n_ptr->next())
1498  if(final_nodes(n_ptr) == n)
1499  return true;
1500 
1501  return false;
1502 }
1503 
1504 
1505 
1507 {
1508  EST_String name;
1509  EST_Litem *l_ptr;
1510  for(l_ptr=l.head();l_ptr!=NULL;l_ptr=l_ptr->next())
1511  name+=nmap_index_to_name(l(l_ptr)) + ",";
1512 
1513  return name;
1514 }
1515 
1516 
1517 
1518 int
1519 Lattice::alphabet_index_lookup(int nmap_index, int qmap_index)
1520 {
1521  symbol_t sym;
1522  sym.nmap_index = nmap_index;
1523  sym.qmap_index = qmap_index;
1524 
1525  return alphabet_symbol_to_index(&sym);
1526 }
1527 
1528 
1531 {
1532  if(index < alphabet.n())
1533  return &(alphabet[index]);
1534  else{
1535  cerr << "Warning : alphabet index " << index << " out of range" << endl;
1536  return NULL;
1537  }
1538 
1539 }
1540 
1541 int
1543 {
1544 
1545  int i,j,mid;
1546 
1547  // binary search
1548  i=0;
1549  j=alphabet.n()-1;
1550 
1551  while(true){
1552 
1553  mid = (i+j)/2;
1554 
1555  if(*sym > alphabet(mid))
1556  i = mid;
1557 
1558  else if(*sym < alphabet(mid))
1559  j = mid;
1560 
1561  else // *sym == alphabet(mid)
1562  return mid; // lucky strike
1563 
1564  if(i==j){
1565  if(*sym == alphabet(i))
1566  return i;
1567  else{
1568  cerr << "Lattice::alphabet_symbol_to_index failed for '"
1569  << *sym << "' 1" << endl;
1570  return -1;
1571  }
1572 
1573  }else if(j==i+1){
1574 
1575  if(*sym == alphabet(i))
1576  return i;
1577  else if(*sym == alphabet(j))
1578  return j;
1579  else{
1580  cerr << "Lattice::alphabet_symbol_to_index failed for '"
1581  << *sym << "' 2" << endl;
1582 
1583  cerr << i << " " << alphabet(i) << endl;
1584  cerr << j << " " << alphabet(j) << endl;
1585 
1586  return -1;
1587  }
1588 
1589  }
1590 
1591  }
1592 
1593  return -1;
1594 
1595 }
1596 
1597 
1598 bool
1600 {
1601 
1602  // different representation of the network , currently only for DFAs
1603  // since for a NFA each tf cell would be a list
1604 
1605  int i,j;
1606  EST_Litem *n_ptr,*a_ptr;
1607  int num_nodes = nodes.length();
1608  int num_symbols = alphabet.n();
1609 
1610  if (num_nodes <= 0) {
1611  cerr << "No nodes, no transition function" << endl;
1612  return true;
1613  }
1614  if(tf != NULL)
1615  cerr << "Warning : discarding existing transition function" << endl;
1616 
1617 
1618  tf = new int*[num_nodes];
1619  for(i=0;i<num_nodes;i++)
1620  tf[i] = new int[num_symbols];
1621 
1622  if(tf == NULL){
1623  cerr << "Not enough memory to build transition function"
1624  << "(needed " << num_nodes*num_symbols*sizeof(int) << " bytes)" << endl;
1625  return false;
1626  }
1627 
1628  for(i=0,n_ptr=nodes.head();n_ptr!=NULL;n_ptr=n_ptr->next(),i++){
1629 
1630  cerr << "building transition function " << (int)((float)(i+1)*100/(float)num_nodes) << "% \r";
1631 
1632  for(j=0;j<alphabet.n();j++){
1633 
1634  tf[i][j]=-1; // means no transition
1635  for(a_ptr=nodes(n_ptr)->arcs_out.head();a_ptr!=NULL;a_ptr=a_ptr->next()){
1636 
1637  if(j == nodes(n_ptr)->arcs_out(a_ptr)->label){
1638  tf[i][j] = node_index(nodes(n_ptr)->arcs_out(a_ptr)->to);
1639  break;
1640  }
1641  }
1642  }
1643  }
1644 
1645  cerr << endl;
1646  return true;
1647 }
1648 
1649 
1650 
1651 bool
1653 {
1654  (void) string;
1655  return false;
1656 }
1657 
1658 
1659 float
1661  EST_TList<Arc*> &path,
1662  EST_Litem *current_symbol,
1663  Node *start_node)
1664 {
1665 
1666  // finds maximum sum-of-probs path
1667  EST_Litem *a_ptr,*best;
1668 
1669  if(start_node == NULL){
1670  start_node = nodes(nodes.head());
1671  current_symbol = input.head();
1672  path.clear();
1673  }
1674 
1675  if(current_symbol == NULL){ // consumed all input
1676  if( final(start_node) )
1677  return 0; // log prob 1
1678 
1679  else
1680  return -10000000; // hack for now
1681 
1682  }
1683 
1684  best=NULL;
1685  float max=-10000000; // hack for now
1686  for (a_ptr = start_node->arcs_out.head(); a_ptr != 0; a_ptr = a_ptr->next()){
1687 
1688  if( alphabet_index_to_symbol(start_node->arcs_out(a_ptr)->label)->nmap_index
1689  == nmap_name_to_index(input(current_symbol)) ){
1690 
1691  float x = viterbi_transduce(input,
1692  path,
1693  current_symbol->next(),
1694  start_node->arcs_out(a_ptr)->to)
1695  + qmap_index_to_value(alphabet_index_to_symbol(start_node->arcs_out(a_ptr)->label)->qmap_index);
1696 
1697  if(x > max){
1698  max = x;
1699  best = a_ptr;
1700  }
1701  }
1702  }
1703 
1704  if(best != NULL)
1705  path.append(start_node->arcs_out(best));
1706 
1707  return max;
1708 
1709 }
1710 
1711 
1713  EST_TList<Arc*> &path,
1714  float &score,
1715  ssize_t current_frame,
1716  Node *start_node)
1717 {
1718  // finds maximum sum-of-probs path
1719  EST_Litem *a_ptr,*best;
1720 
1721  if(start_node == NULL){
1722  start_node = nodes(nodes.head());
1723  current_frame = 0;
1724  path.clear();
1725  score = 0.0;
1726  }
1727 
1728  if(current_frame == observations.num_frames()){ // consumed all input
1729  if( final(start_node) )
1730  return 0; // log prob 1
1731 
1732  else
1733  return -10000000; // hack for now
1734 
1735  }
1736 
1737 
1738  if(score < -100000){ // hack !
1739  return -10000000;
1740  }
1741 
1742  best=NULL;
1743  float max=-10000000; // hack for now
1744  for (a_ptr = start_node->arcs_out.head(); a_ptr != 0; a_ptr = a_ptr->next()){
1745 
1746  ssize_t observation_element =
1747  alphabet_index_to_symbol(start_node->arcs_out(a_ptr)->label)->nmap_index
1748  - 2; // HACK !!@!!!! to skip ENTER/EXIT
1749 
1750  float this_observation = observations.a(current_frame,observation_element);
1751 
1752  //cerr << "frame " << current_frame << "," << observation_element
1753  //<< " : " << this_observation << endl;
1754 
1755  float x = viterbi_transduce(observations,
1756  path,
1757  score,
1758  current_frame+1,
1759  start_node->arcs_out(a_ptr)->to)
1760 
1761  + qmap_index_to_value(alphabet_index_to_symbol(start_node->arcs_out(a_ptr)->label)->qmap_index)
1762 
1763  + this_observation;
1764 
1765  if(x > max){
1766  max = x;
1767  best = a_ptr;
1768  }
1769 
1770  }
1771 
1772  if(best != NULL){
1773  path.append(start_node->arcs_out(best));
1774 
1775  int observation_element =
1776  alphabet_index_to_symbol(start_node->arcs_out(best)->label)->nmap_index;
1777 
1778  float this_observation = observations.a(current_frame,observation_element);
1779 
1780  score += qmap_index_to_value(alphabet_index_to_symbol(start_node->arcs_out(best)->label)->qmap_index) + this_observation;
1781 ;
1782 
1783  }
1784 
1785  cerr << max << endl;
1786 
1787  return max;
1788 
1789 }
1790 
1791 // hack for now (required for SHARED=2)
1793 return false;
1794 }
1795 
1796 
1797 
1798 
float mid(const EST_Item &item)
Definition: EST_item_aux.cc:69
symbol_t * alphabet_index_to_symbol(int index)
void qsort(EST_TList< T > &a)
EST_String name_as_string(EST_IList &l)
bool build_transition_function()
bool build_distinguished_state_table(bool **&dst)
Definition: EST_lattice.cc:717
void sort_unique(EST_TList< T > &l)
Definition: EST_TList.h:317
bool final(Node *n)
EST_String nmap_index_to_name(int index)
EST_UItem * prev()
Definition: EST_UList.h:56
bool minimise()
Definition: EST_lattice.cc:922
int alphabet_index_lookup(int nmap_index, int qmap_index)
float qmap_index_to_value(int index)
void remove_arc_from_nodes_out_list(Node *n, Arc *a)
void ptr_qsort(EST_TList< T > &a)
Definition: EST_TList.h:311
int qmap_value_to_index(float value)
bool build_distinguished_state_table_from_transition_function(bool **&dst)
Definition: EST_lattice.cc:868
int ssize_t
int index(EST_TList< T > &l, T &val, bool(*eq)(const EST_UItem *, const EST_UItem *)=NULL)
Definition: EST_TList.h:286
EST_UItem * next()
Definition: EST_UList.h:55
void prune_arcs(Node *node, EST_TList< Arc * > arcs)
float max(float a, float b)
Definition: EST_cluster.cc:143
bool build_distinguished_state_table_direct(bool **&dst)
Definition: EST_lattice.cc:782
bool determinise()
Definition: EST_lattice.cc:432
int alphabet_symbol_to_index(symbol_t *sym)
void sort_by_label(EST_TList< Lattice::Arc * > &l)
Definition: EST_lattice.cc:711
bool operator!=(const symbol_t &s2) const
float & a(ssize_t i, int c=0)
Definition: EST_Track.cc:1025
bool accepts(EST_TList< symbol_t * > &string)
EST_UItem * n
Definition: EST_UList.h:53
EST_IList name
Definition: EST_lattice.h:83
EST_Item * link(int l, EST_Item *n)
void merge_nodes(EST_TList< Node * > &l)
int nmap_name_to_index(const EST_String &name)
void sort_arc_lists()
Definition: EST_lattice.cc:695
NULL
Definition: EST_WFST.cc:55
ssize_t num_frames() const
return number of frames in track
Definition: EST_Track.h:651
Node * start_node()
Definition: EST_lattice.cc:60
void merge_sort_unique(EST_TList< T > &l, EST_TList< T > &m)
Definition: EST_TList.h:326
getString int
Definition: EST_item_aux.cc:50
void append(const T &item)
add item onto end of list
Definition: EST_TList.h:196
bool link(Node *n1, Node *n2, int label)
Definition: EST_lattice.cc:665
EST_TList< Arc * > arcs_out
Definition: EST_lattice.h:84
void merge_arcs()
EST_UItem * head() const
Definition: EST_UList.h:97
bool expand()
EST_String
void prune_arc(Node *node, Arc *arc)
float viterbi_transduce(EST_TList< EST_String > &input, EST_TList< Arc * > &path, EST_Litem *current_symbol=NULL, Node *start_node=NULL)
void clear(void)
remove all items in list
Definition: EST_TList.h:244
int node_index(Node *n)