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