Edinburgh Speech Tools  2.4-release
 All Classes Functions Variables Typedefs Enumerations Enumerator Friends Pages
wfst_transduce.cc
1 /*************************************************************************/
2 /* */
3 /* Centre for Speech Technology Research */
4 /* University of Edinburgh, UK */
5 /* Copyright (c) 1997 */
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 : Alan W Black */
34 /* Date : December 1997 */
35 /*-----------------------------------------------------------------------*/
36 /* */
37 /* Transduction using a WFST */
38 /* */
39 /*=======================================================================*/
40 #include <iostream>
41 #include "EST_WFST.h"
42 
43 /** An internal class in transduction of WFSTs holding intermediate
44  state information.
45 */
46 class wfst_tstate {
47  public:
48  int state;
49  EST_IList outs;
50  float score;
51 };
52 
53 ostream &operator << (ostream &s, const wfst_tstate &state)
54 {
55  (void)state;
56  return s << "<<wfst_tstate>>";
57 }
58 
59 Declare_TList(wfst_tstate)
60 
61 #if defined(INSTANTIATE_TEMPLATES)
62 #include "../base_class/EST_TList.cc"
63 
64 Instantiate_TList(wfst_tstate)
65 
66 #endif
67 
68 typedef EST_TList<wfst_tstate> wfst_tstate_list;
69 
70 static void add_transduce_mstate(const EST_WFST &wfst,
71  const wfst_tstate &cs,
72  wfst_translist &tranlist,
73  wfst_tstate_list &ns);
74 
75 int transduce(const EST_WFST &wfst,const EST_StrList &in,EST_StrList &out)
76 {
77  // Map names to internal ints before transduction
78  EST_Litem *p;
79  EST_IList in_i,out_i;
80  int r;
81 
82  for (p=in.head(); p != 0; p=p->next())
83  in_i.append(wfst.in_symbol(in(p)));
84 
85  r = transduce(wfst,in_i,out_i);
86 
87  for (p=out_i.head(); p != 0; p=p->next())
88  out.append(wfst.out_symbol(out_i(p)));
89 
90  return r;
91 }
92 
93 int transduce(const EST_WFST &wfst,const EST_IList &in,EST_IList &out)
94 {
95  // Transduce input stream to an output stream
96  EST_Litem *i,*cs;
97  int r=FALSE;
98  wfst_tstate_list *current_ms = new wfst_tstate_list;
99  wfst_tstate start_state;
100  wfst_translist ss_eps_trans;
101 
102  start_state.state = wfst.start_state();
103  start_state.score = 0;
104  current_ms->append(start_state);
105  // Add any epsilon accessible states
106  wfst.transduce(wfst.start_state(),wfst.in_epsilon(),ss_eps_trans);
107  add_transduce_mstate(wfst,start_state,ss_eps_trans,*current_ms);
108 
109  for (i=in.head(); i != 0; i=i->next())
110  {
111  wfst_tstate_list *ns = new wfst_tstate_list;
112 
113  for (cs=current_ms->head(); cs != 0; cs=cs->next())
114  { // For each state in current update list of new states
115  wfst_translist translist;
116  wfst.transduce((*current_ms)(cs).state,in(i),translist);
117  add_transduce_mstate(wfst,(*current_ms)(cs),translist,*ns);
118  }
119  // Using pointers to avoid having to copy the state list
120  delete current_ms;
121  current_ms = ns;
122 
123  if (current_ms->length() == 0)
124  break; // give up, no transition possible
125  }
126  // current_ms will contain the list of possible transitions
127  if (current_ms->length() > 1)
128  cerr << "WFST: found " << current_ms->length() << " transductions" <<
129  endl;
130  // should find "best" but we'll find longest at present
131  // Choose the longest (should be based on score)
132  for (cs = current_ms->head(); cs != 0; cs=cs->next())
133  {
134  if ((wfst.final((*current_ms)(cs).state)) &&
135  ((*current_ms)(cs).outs.length() > out.length()))
136  {
137  r = TRUE;
138  out = (*current_ms)(cs).outs;
139  }
140  }
141  delete current_ms;
142  return r;
143 }
144 
145 static void add_transduce_mstate(const EST_WFST &wfst,
146  const wfst_tstate &cs,
147  wfst_translist &translist,
148  wfst_tstate_list &ns)
149 {
150  // For each possible transduction of in from cs.state in WFST
151  // add it to ns.
152  // This should really only add states if they are not already there
153  // but you really need stae plus recognized path to get all
154  // transductions so a tree structure would be better.
155  EST_Litem *t;
156 
157  // Add new states to ns if not already there
158  for (t=translist.head(); t != 0; t=t->next())
159  {
160  // Declare a new one and put it on the end of the list
161  // before we fill its values, this saves a copy
162  wfst_tstate tts;
163  ns.append(tts);
164  wfst_tstate &ts = ns.last();
165 
166  ts.state = translist(t)->state();
167  // the combination is probably WFST dependant
168  ts.score = translist(t)->weight()+cs.score;
169  // copying the outs up to now (pity)
170  ts.outs = cs.outs;
171  ts.outs.append(translist(t)->out_symbol());
172 
173  // Also any potential epsilon transitions for this new state
174  wfst_translist etranslist;
175  wfst.transduce(ts.state,wfst.in_epsilon(),etranslist);
176  add_transduce_mstate(wfst,ts,etranslist,ns);
177  }
178 }
179 
180 int recognize(const EST_WFST &wfst,const EST_StrList &in,int quiet)
181 {
182  // Map names to internal ints before recognition
183  EST_Litem *p;
184  EST_IList in_i,out_i;
185  int i,o;
186  int r;
187 
188  for (p=in.head(); p != 0; p=p->next())
189  {
190  if (in(p).contains("/"))
191  {
192  i = wfst.in_symbol(in(p).before("/"));
193  o = wfst.out_symbol(in(p).after("/"));
194  }
195  else
196  {
197  i = wfst.in_symbol(in(p));
198  o = wfst.out_symbol(in(p));
199  }
200  in_i.append(i);
201  out_i.append(o);
202  }
203 
204  r = recognize(wfst,in_i,out_i,quiet);
205 
206  return r;
207 }
208 
209 int recognize(const EST_WFST &wfst,const EST_IList &in,
210  const EST_IList &out, int quiet)
211 {
212  int state = wfst.start_state();
213  EST_Litem *p,*q;
214  int nstate;
215 
216  for (p=in.head(),q=out.head();
217  ((p != 0) && (q != 0));
218  p=p->next(),q=q->next())
219  {
220  nstate = wfst.transition(state,in(p),out(q));
221  if (!quiet)
222  printf("state %d %s/%s -> %d\n",state,
223  (const char *)wfst.in_symbol(in(p)),
224  (const char *)wfst.out_symbol(out(q)),
225  nstate);
226  state = nstate;
227  if (state == WFST_ERROR_STATE)
228  return FALSE;
229  }
230 
231  if (p != q)
232  {
233  cerr << "wfst recognize: in/out tapes of different lengths"
234  << endl;
235  return FALSE;
236  }
237 
238  if (wfst.final(state))
239  return TRUE;
240  else
241  return FALSE;
242 }
243 
244 int recognize_for_perplexity(const EST_WFST &wfst,
245  const EST_StrList &in,
246  int quiet,
247  float &count,
248  float &sumlogp)
249 {
250  // Map names to internal ints before recognition
251  EST_Litem *p;
252  EST_IList in_i,out_i;
253  int i,o;
254  int r;
255 
256  for (p=in.head(); p != 0; p=p->next())
257  {
258  if (in(p).contains("/"))
259  {
260  i = wfst.in_symbol(in(p).before("/"));
261  o = wfst.out_symbol(in(p).after("/"));
262  }
263  else
264  {
265  i = wfst.in_symbol(in(p));
266  o = wfst.out_symbol(in(p));
267  }
268  in_i.append(i);
269  out_i.append(o);
270  }
271 
272  r = recognize_for_perplexity(wfst,in_i,out_i,quiet,count,sumlogp);
273 
274  return r;
275 }
276 
277 int recognize_for_perplexity(const EST_WFST &wfst,
278  const EST_IList &in,
279  const EST_IList &out,
280  int quiet,
281  float &count,
282  float &sumlogp)
283 {
284  int state = wfst.start_state();
285  EST_Litem *p,*q;
286  int nstate;
287  float prob;
288  count = 0;
289  sumlogp = 0;
290 
291  for (p=in.head(),q=out.head();
292  ((p != 0) && (q != 0));
293  p=p->next(),q=q->next())
294  {
295  nstate = wfst.transition(state,in(p),out(q),prob);
296  count++;
297  if (prob > 0)
298  sumlogp += log(prob);
299  else
300  sumlogp += -100; // bad hack
301  if (!quiet)
302  printf("state %d %s/%s -> %d\n",state,
303  (const char *)wfst.in_symbol(in(p)),
304  (const char *)wfst.out_symbol(out(q)),
305  nstate);
306  state = nstate;
307  if (state == WFST_ERROR_STATE)
308  return FALSE;
309  }
310 
311  if (p != q)
312  {
313  cerr << "wfst recognize: in/out tapes of different lengths"
314  << endl;
315  return FALSE;
316  }
317 
318  if (wfst.final(state))
319  return TRUE;
320  else
321  return FALSE;
322 }
323