Edinburgh Speech Tools  2.1-release
dynamic_program.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 : June 1998 */
35 /*************************************************************************/
36 
37 #include <cstdlib>
38 #include <cstdio>
39 #include <iostream>
40 #include <fstream>
41 #include "EST_math.h"
43 
44 using namespace std;
45 
47 static EST_Item *const def_val_item_ptr = NULL;
48 template <> EST_Item* const *EST_Item_ptr_Vector::def_val = &def_val_item_ptr;
49 
50 static EST_Item* error_return_item_ptr = NULL;
51 template <> EST_Item* *EST_Item_ptr_Vector::error_return = &error_return_item_ptr;
52 
53 #if defined(INSTANTIATE_TEMPLATES)
54 
55 #include "../base_class/EST_TVector.cc"
56 
57 template class EST_TVector<EST_Item*>;
58 
59 #endif
60 
61 typedef
62 float (*local_cost_function)(const EST_Item *item1,
63  const EST_Item *item2);
64 
65 typedef
67  const int j,
68  const int max_i,
69  const int max_j);
70 
71 bool dp_sub(int i, int j,
72  const EST_Item_ptr_Vector &vr1,
73  const EST_Item_ptr_Vector &vr2,
77  EST_Item *null_sym,
78  EST_FMatrix &cost);
79 
80 int trace_back_and_link(int i, int j,
81  EST_Item *p1, EST_Item *p2,
82  const EST_IMatrix &DP_path_i,
83  const EST_IMatrix &DP_path_j,
84  EST_Item *null_sym);
85 
86 inline bool null_lpf(const int,const int,const int,const int)
87 {
88  return FALSE;
89 }
90 
91 bool dp_match(const EST_Relation &lexical,
92  const EST_Relation &surface,
93  EST_Relation &match,
96  EST_Item *null_sym);
97 
98 
99 bool dp_match(const EST_Relation &lexical,
100  const EST_Relation &surface,
101  EST_Relation &match,
103  EST_Item *null_sym)
104 {
105  // dp without pruning
106 
107  return dp_match(lexical,surface,match,lcf,null_lpf,null_sym);
108 
109 }
110 
111 static float fixed_ins;
112 static float fixed_del;
113 static float fixed_sub;
114 
115 float fixed_local_cost(const EST_Item *s1, const EST_Item *s2)
116 {
117  EST_String null_sym = "nil";
118 
119  // otherwise cost is either insertion cost, or cost_matrix value
120  if (s1->name() == s2->name())
121  return 0;
122  else
123  {
124  if (s1->name() == null_sym)
125  return fixed_ins;
126  else if (s2->name() == null_sym)
127  return fixed_del;
128  else
129  return fixed_sub;
130  }
131 }
132 
133 
134 bool dp_match(const EST_Relation &lexical,
135  const EST_Relation &surface,
136  EST_Relation &match,
137  float ins, float del, float sub)
138 {
139  fixed_ins = ins;
140  fixed_del = del;
141  fixed_sub = sub;
142  EST_Item null_sym;
143 
144  return dp_match(lexical, surface, match, fixed_local_cost,
145  null_lpf, &null_sym);
146 }
147 
148 
149 bool dp_match(const EST_Relation &lexical,
150  const EST_Relation &surface,
151  EST_Relation &match,
154  EST_Item *null_sym)
155 {
156 
157 
158  // aligns lexical and surface forms using dynamic programming
159  // i.e. the lexical form is transformed into the surface form
160  // by substitutions, insertions and deletions
161 
162  // makes links between associated (matching or substituted) items
163  // insertions and deletions are 'left dangling'
164  // links are stored in a new relation called "Match"
165 
166  // assumes that local cost computation is cheap (no caching)
167 
169  EST_Item_ptr_Vector vr1,vr2;
170  EST_Item *p;
171  int l1,l2,i,j;
172 
173  l1 = lexical.length() + 1;
174  l2 = surface.length() + 1;
175 
176  vr1.resize(l1);
177  vr2.resize(l2);
178 
179  // prepend null_syms
180  vr1[0] = null_sym;
181  vr2[0] = null_sym;
182 
183  for (p=lexical.head(),i=1; p != 0; p = p->next(),i++)
184  vr1[i] = p;
185  for (p=surface.head(),i=1; p != 0; p = p->next(),i++)
186  vr2[i] = p;
187 
188  DP_path_i.resize(l1,l2);
189  DP_path_j.resize(l1,l2);
190 
191 /*
192  cerr << "Pruning" << endl;
193  for(i=0;i<l1;i++)
194  {
195  for(j=0;j<l2;j++)
196  if(lpf(i,j,l1,l2))
197  cerr << "- ";
198  else
199  cerr << "+ ";
200  cerr << endl;
201  }
202  cerr << endl;
203 */
204 
205  // end conditions : must start at (0,0) and finish at (l1-1,l2-1)
206  // i.e. extreme corners of grid
207  EST_FMatrix cost;
208  cost.resize(vr1.length(),vr2.length());
209  for(i=0;i<l1;i++)
210  for(j=0;j<l2;j++)
211  cost.a_no_check(i,j) = -1; // means not computed yet
212 
213  if(!dp_sub(l1-1,l2-1,
214  vr1,vr2,
215  DP_path_i,DP_path_j,
216  lcf,lpf,null_sym,cost))
217  {
218  cerr << "No path found (over pruning ?)" << endl;
219  return FALSE;
220  }
221  // make somewhere to record the relations
222  //utt.create_relation("Match");
223  for (p = lexical.head(); p; p = p->next())
224  match.append(p);
225 
226  /*
227  for(i=0;i<l1;i++)
228  {
229  for(j=0;j<l2;j++)
230  cerr << i << "," << j << "=[" << DP_path_i(i,j) << "," << DP_path_j(i,j) << "] ";
231  cerr << endl;
232  }
233  cerr << endl;
234 */
235 
236  trace_back_and_link(l1-1,l2-1,
237  match.last(),
238  surface.last(),
239  DP_path_i,DP_path_j,null_sym);
240 
241  return TRUE;
242 }
243 
244 
245 bool dp_sub(int i, int j,
246  const EST_Item_ptr_Vector &vr1,
247  const EST_Item_ptr_Vector &vr2,
249  local_cost_function lcf,
251  EST_Item *null_sym,
252  EST_FMatrix &cost)
253 {
254 
255  // the goal is to compute cost(i,j)
256 
257  // already done ?
258  if(cost(i,j) >= 0)
259  return TRUE;
260 
261  //cerr << "sub " << i << " " << j << endl;
262 
263  int best_i=-1,best_j=-1;
264  float sub,ins,del;
265  float best_c=MAXFLOAT;
266 
267  // prune ?
268  if(lpf(i,j,vr1.length()-1,vr2.length()-1))
269  return FALSE;
270 
271 
272  // consider all paths into this point
273  // and select the best one (lowest cost)
274 
275  if(i==0)
276  {
277  if(j==0)
278  {
279 
280  best_i = i;
281  best_j = j;
282  best_c = lcf(null_sym,null_sym);
283  }
284  else
285  {
286 
287  // insert j'th item from vr2
288  if(dp_sub(i,j-1,vr1,vr2,
289  DP_path_i,DP_path_j,
290  lcf,lpf, null_sym,cost))
291  {
292  best_i = i;
293  best_j = j-1;
294  best_c = lcf(null_sym,vr2(j)) + cost.a(i,j-1);
295  }
296  else
297  return FALSE;
298  }
299  }
300 
301  else if(j==0)
302  {
303 
304  // delete i'th item from vr1
305  if(dp_sub(i-1,j,vr1,vr2,
306  DP_path_i,DP_path_j,
307  lcf,lpf, null_sym,cost))
308  {
309  best_i = i-1;
310  best_j = j;
311  best_c = lcf(vr1(i),null_sym) + cost.a(i-1,j);
312  }
313 
314  }
315 
316  // this is the simplest local constraint (i.e. no constraints !)
317  // which allows unlimited consecutive insertions or deletions
318 
319  else
320  {
321 
322  if(dp_sub(i-1,j-1,vr1,vr2,
323  DP_path_i,DP_path_j,
324  lcf,lpf, null_sym,cost))
325  {
326  sub = 2 * lcf(vr1(i),vr2(j)) + cost(i-1,j-1);
327  if(sub < best_c)
328  {
329  best_i=i-1;
330  best_j=j-1;
331  best_c = sub;
332  }
333  }
334 
335  if(dp_sub(i,j-1,vr1,vr2,
336  DP_path_i,DP_path_j,
337  lcf,lpf, null_sym,cost))
338  {
339  ins=lcf(null_sym,vr2(j)) + cost(i,j-1);
340  if(ins < best_c)
341  {
342  best_i=i;
343  best_j=j-1;
344  best_c = ins;
345  }
346  }
347 
348  if(dp_sub(i-1,j,vr1,vr2,
349  DP_path_i,DP_path_j,
350  lcf,lpf, null_sym,cost))
351  {
352  del=lcf(vr1(i),null_sym) + cost(i-1,j);
353  if(del < best_c)
354  {
355  best_i=i-1;
356  best_j=j;
357  best_c = del;
358  }
359  }
360  }
361 
362  cost.a(i,j) = best_c;
363  DP_path_i.a_no_check(i,j) = best_i;
364  DP_path_j.a_no_check(i,j) = best_j;
365 
366 
367  //cerr << "best " << i << "," << j << " = " << best_c << endl;
368 
369  if(best_c == MAXFLOAT)
370  // didn't find a better path
371  return FALSE;
372  else
373  return TRUE;
374 
375 }
376 
377 
378 int trace_back_and_link(int i, int j,
379  EST_Item *p1, EST_Item *p2,
380  const EST_IMatrix &DP_path_i,
381  const EST_IMatrix &DP_path_j,
382  EST_Item *null_sym)
383 {
384 
385  //cerr << "trace " << i << " " << j << endl;
386 
387 
388  //int i,j;
389  //i=utt.relation("Lexical")->index(p1);
390  //j=utt.relation("Surface")->index(p2);
391 
392  if((p1==0)&&(p2==0)) // reached start
393  return TRUE;
394 
395  if(DP_path_i(i,j) == i-1)
396  {
397  if(DP_path_j(i,j) == j-1)
398  {
399  // match, or substitution
400  //cerr << "sub " << p1->name() << " with " << p2->name() << endl;
401  if ((p1 == 0) || (p2 == 0)) {
402  cerr << "trace back and link: Wrong dynamic programming " <<
403  "path or wrong items at (i=" << i <<", j=" << j <<")" <<
404  endl;
405  return FALSE;
406  }
407  p1->append_daughter(p2);
408  p1=p1->prev();
409  p2=p2->prev();
410  }
411  else
412  {
413  // deletion
414  if (p1 == 0) {
415  cerr << "trace back and link: Wrong dynamic programming " <<
416  "path or wrong item p1 at (i=" << i <<", j=" << j <<")" <<
417  endl;
418  return FALSE;
419  }
420  p1=p1->prev();
421  }
422  }
423  else
424  {
425  // insertion
426  // p1->append_daughter(p2); // decorative
427  if (p2 == 0) {
428  cerr << "trace back and link: Wrong dynamic programming " <<
429  "path or wrong item p2 at (i=" << i <<", j=" << j <<")" <<
430  endl;
431  return FALSE;
432  }
433  p2=p2->prev();
434  }
435 
436  return trace_back_and_link(DP_path_i(i,j), DP_path_j(i,j),
437  p1,p2,
438  DP_path_i,DP_path_j,
439  null_sym);
440 }
441 
EST_Item * head() const
Definition: EST_Relation.h:121
const EST_String name() const
Definition: EST_Item.h:250
float(* local_cost_function)(const EST_Item *item1, const EST_Item *item2)
EST_DMatrix * error_return
EST_Item * append_daughter(EST_Item *li=0)
Definition: EST_Item.cc:425
float fixed_local_cost(const EST_Item *s1, const EST_Item *s2)
bool dp_match(const EST_Relation &lexical, const EST_Relation &surface, EST_Relation &match, local_cost_function lcf, local_pruning_function lpf, EST_Item *null_sym)
int trace_back_and_link(int i, int j, EST_Item *p1, EST_Item *p2, const EST_IMatrix &DP_path_i, const EST_IMatrix &DP_path_j, EST_Item *null_sym)
int length() const
const T & a(ssize_t row, ssize_t col) const
Definition: EST_TMatrix.h:196
const EST_DMatrix * def_val
EST_Item * last() const
Definition: EST_Relation.h:132
bool null_lpf(const int, const int, const int, const int)
void resize(ssize_t n, int set=1)
Definition: EST_TVector.cc:196
#define MAXFLOAT
Definition: EST_math.h:131
INLINE ssize_t length() const
number of items in vector.
Definition: EST_TVector.h:249
EST_TVector< EST_Item * > EST_Item_ptr_Vector
EST_FMatrix sub(const EST_FMatrix &a, ssize_t row, ssize_t col)
Definition: vec_mat_aux.cc:187
EST_Item * prev() const
Definition: EST_Item.h:350
#define l2
#define FALSE
Definition: EST_bool.h:119
NULL
Definition: EST_WFST.cc:55
bool(* local_pruning_function)(const int i, const int j, const int max_i, const int max_j)
EST_Item * next() const
Definition: EST_Item.h:348
bool dp_sub(int i, int j, const EST_Item_ptr_Vector &vr1, const EST_Item_ptr_Vector &vr2, EST_IMatrix &DP_path_i, EST_IMatrix &DP_path_j, local_cost_function lcf, local_pruning_function lpf, EST_Item *null_sym, EST_FMatrix &cost)
EST_IMatrix DP_path_i
Definition: dp_main.cc:90
Template vector.
Definition: EST_TVector.h:145
INLINE const T & a_no_check(ssize_t row, ssize_t col) const
const access with no bounds check, care recommend
Definition: EST_TMatrix.h:182
#define l1
void resize(int rows, int cols, int set=1)
resize matrix
EST_Item * append(EST_Item *si)
Definition: EST_Relation.cc:88
#define TRUE
Definition: EST_bool.h:118
#define bool
Definition: EST_bool.h:117
EST_IMatrix DP_path_j
Definition: dp_main.cc:90