Edinburgh Speech Tools  2.1-release
dp_main.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 : May 1998 */
35 /*-----------------------------------------------------------------------*/
36 /* Simple dynamic programming */
37 /* e.g. for aligning pronunciations */
38 /*=======================================================================*/
39 
40 #include <cstdlib>
41 #include <cstdio>
42 #include <cmath>
43 #include "EST.h"
44 
45 using namespace std;
46 
48  const EST_String &filename,
49  const int vec_len);
50 
51 typedef
52 float (*local_cost_function)(const EST_Item *item1,
53  const EST_Item *item2);
54 
55 typedef
57  const int j,
58  const int max_i,
59  const int max_j);
60 
61 bool dp_match(const EST_Relation &lexical,
62  const EST_Relation &surface,
63  EST_Relation &match,
66  EST_Item *null_sym);
67 
68 bool dp_match(const EST_Relation &lexical,
69  const EST_Relation &surface,
70  EST_Relation &match,
72  EST_Item *null_sym);
73 
74 float local_cost(const EST_Item *s1, const EST_Item *s2);
75 bool local_prune(const int i, const int j,
76  const int max_i,const int max_j);
77 static void load_vocab(const EST_String &vfile);
78 static EST_Item *null_sym;
79 //static EST_String deleted_marker = "<del>";
80 //static EST_String inserted_marker = "<ins>";
81 static bool show_cost=FALSE;
82 static int prune_width = 100;
83 
86 
92 
93 // this are local distance measures,
94 // NOT the 1/2/1 weights in the DP recursion formula !
95 float insertion_cost = 1;
96 float deletion_cost = 1;
98 
99 
100 // two possibilities :
101 // 1. simple insertion/deletion/substitution penalties
102 // 2. matrix of distances between all pairs of vocab items,
103 // where vocab includes some null symbol for insertions/deletions
104 
105 EST_String distance_measure = "simple"; // could be "matrix"
106 
107 
108 int main(int argc, char **argv)
109 {
110  EST_StrList files;
111  EST_Option al;
112  EST_String out_file;
113  //int i;
114  EST_Relation *path1, *path2, *match;
115 
116  null_sym = new EST_Item;
117  null_sym->set_name("<null>");
118 
119  parse_command_line(argc, argv,
120  EST_String("Usage:\n")+
121  "dp <options> \"pattern 1\" \"pattern 2\"\n"+
122  "Find the best alignment of a pair of symbol sequences (e.g. word pronuciations).\n"+
123  "-vocab <string> file containing vocabulary\n"+
124  "-place_holder <string> which vocab item is the place holder (default is " + null_sym->name() + " )\n"+
125  "-show_cost show cost of matching path\n"+
126  "-o <string> output file\n"+
127  "-p <int> 'beam' width\n"+
128  "Either:\n"+
129  "-i <float> insertion cost\n"+
130  "-d <float> deletion cost\n"+
131  "-s <float> substitution cost\n"+
132  "Or:\n"+
133  "-cost_matrix <string> file containing cost matrix\n",
134  files, al);
135 
136  out_file = al.present("-o") ? al.val("-o") : (EST_String)"-";
137 
138  if (al.present("-vocab"))
139  load_vocab(al.val("-vocab"));
140  else
141  {
142  cerr << argv[0] << ": no vocab file specified" << endl;
143  exit(-1);
144  }
145 
146  if (al.present("-p"))
147  prune_width = al.ival("-p");
148 
149  if (al.present("-cost_matrix"))
150  {
151  if(al.present("-i") || al.present("-d") || al.present("-s") )
152  {
153  cerr << "Can't have ins/del/subs costs as well as matrix !" << endl;
154  exit(-1);
155  }
156  distance_measure="matrix";
157  cost_matrix.load(al.val("-cost_matrix"));
158 
159  if(al.present("-place_holder"))
160  null_sym->set_name(al.val("-place_holder"));
161 
162  if(StrVector_index(vocab,null_sym->name()) < 0)
163  {
164  cerr << "The place holder symbol '" << null_sym->name();
165  cerr << "' is not in the vocbulary !" << endl;
166  exit(-1);
167  }
168 
169  if(cost_matrix.num_columns() != vocab.length())
170  {
171  cerr << "Cost matrix number of columns must match vocabulary size !" << endl;
172  exit(-1);
173  }
174  if(cost_matrix.num_rows() != vocab.length())
175  {
176  cerr << "Cost matrix number of rows must match vocabulary size !" << endl;
177  exit(-1);
178  }
179 
180  }
181  else if(al.present("-i") && al.present("-d") && al.present("-s") )
182  {
183  insertion_cost = al.fval("-i");
184  deletion_cost = al.fval("-d");
185  substitution_cost = al.fval("-s");
186  }
187  else
188  {
189  cerr << "Must give either ins/del/subs costs or cost matrix !" << endl;
190  exit(-1);
191  }
192 
193 
194  if(al.present("-show_cost"))
195  show_cost=TRUE;
196 
197  if(files.length() != 2)
198  {
199  cerr << "Must give 2 patterns !" << endl;
200  exit(-1);
201  }
202 
203  StringtoStrList(files(files.head()),pattern1_l," ");
204  StringtoStrList(files(files.head()->next()),pattern2_l," ");
205 
206  EST_Utterance utt;
207  path1 = utt.create_relation("Lexical");
208  path2 = utt.create_relation("Surface");
209  match = utt.create_relation("Match");
210 
211  EST_Litem *p;
212  for(p=pattern1_l.head();p != 0; p=p->next())
213  {
214  if( StrVector_index(vocab,pattern1_l(p)) < 0)
215  {
216  cerr << pattern1_l(p) << " is not in the vocabulary !" << endl;
217  exit(1);
218  }
219  EST_Item new_item;
220  new_item.set_name(pattern1_l(p));
221  path1->append(&new_item);
222  }
223 
224  for(p=pattern2_l.head();p != 0; p=p->next())
225  {
226  if( StrVector_index(vocab,pattern2_l(p)) < 0)
227  {
228  cerr << pattern2_l(p) << " is not in the vocabulary !" << endl;
229  exit(1);
230  }
231  EST_Item new_item;
232  new_item.set_name(pattern2_l(p));
233  path2->append(&new_item);
234  }
235 
236  // to do : check all items in two patterns are in vocab
237  // .....
238 
239 
240 // cerr << "MATCHING..." << endl;
241  if(!dp_match(*path1,*path2,*match,
242  local_cost,local_prune,null_sym))
243 // cerr << "OK !" << endl;
244 // else
245  cerr << "No match could be found." << endl;
246 
247 
248  utt.save(out_file);
249 
250 
251  return 0;
252 }
253 
254 
255 static void load_vocab(const EST_String &vfile)
256 {
257  // Load vocabulary (strings)
258  EST_TokenStream ts;
259 
260  if (ts.open(vfile) == -1)
261  {
262  cerr << "can't find vocab file \"" << vfile << "\"" << endl;
263  exit(-1);
264  }
265 
266  while (!ts.eof())
267  if (ts.peek() != "")
268  vocab_l.append(ts.get().string());
269 
270  ts.close();
271 
272  StrList_to_StrVector(vocab_l,vocab);
273 }
274 
275 
276 float local_cost(const EST_Item *s1, const EST_Item *s2)
277 {
278  // N.B. cost is not necessarily zero for matching symbols
279 
280  //cerr << "lcf " << s1 << "," << s2 << endl;
281 
282  // otherwise cost is either insertion cost, or cost_matrix value
283  if(distance_measure == "simple")
284  {
285  if(s1->name() == s2->name())
286  return 0;
287  else
288  {
289  if(s1 == null_sym)
290  return insertion_cost;
291  else if(s2 == null_sym)
292  return deletion_cost;
293  else
294  return substitution_cost;
295  }
296  }
297 
298  //cerr << "Cost of replacing " << s1 << " with " << s2 << " is ";
299  //cerr << cost_matrix(StrVector_index(vocab,s1),StrVector_index(vocab,s2)) << endl;
300 
301  return cost_matrix(StrVector_index(vocab,s1->name()),
302  StrVector_index(vocab,s2->name()));
303 
304 }
305 
306 bool local_prune(const int i, const int j,
307  const int max_i, const int max_j)
308 {
309 
310  // keep it simple :
311  // if we stray too far from the diagonal - PRUNE !
312 
313  float scale = (float)max_i / (float)max_j;
314 
315  float near_j = (float)i / scale;
316  float near_i = (float)j * scale;
317 
318  /*
319  cerr << "prune i: " << i << " " << near_i - (float)i
320  << " " << abs(near_i - (float)i)<< endl;
321  cerr << "prune j: " << j << " " << near_j - (float)j
322  << " " << abs(near_j - (float)j) << endl;
323  */
324 
325  if( (abs((int)(near_i - (float)i)) > prune_width) ||
326  (abs((int)(near_j - (float)j)) > prune_width) )
327  {
328  //cerr << "lpf " << i << "," << j << " true" << endl;
329  return TRUE;
330  }
331 
332  return FALSE;
333 
334 }
EST_TokenStream & get(EST_Token &t)
get next token in stream
Definition: EST_Token.cc:499
const EST_String name() const
Definition: EST_Item.h:250
EST_write_status save(const EST_String &filename, const EST_String &type="est_ascii") const
void StrList_to_StrVector(EST_StrList &l, EST_StrVector &v)
Convert a list of strings to a vector of strings.
EST_FVector DP_insertion_cost
Definition: dp_main.cc:89
EST_Relation * create_relation(const EST_String &relname)
create a new relation called n.
ssize_t num_columns() const
return number of columns
Definition: EST_TMatrix.h:179
A vector class for floating point numbers. EST_FVector x should be used instead of float *x wherever ...
Definition: EST_FMatrix.h:119
int ival(const EST_String &rkey, int m=1) const
Definition: EST_Option.cc:82
EST_read_status load_TList_of_StrVector(EST_TList< EST_StrVector > &w, const EST_String &filename, const int vec_len)
Definition: EST_svec_aux.cc:54
bool local_prune(const int i, const int j, const int max_i, const int max_j)
Definition: dp_main.cc:306
void close(void)
Close stream.
Definition: EST_Token.cc:419
ssize_t num_rows() const
return number of rows
Definition: EST_TMatrix.h:177
float fval(const EST_String &rkey, int m=1) const
Definition: EST_Option.cc:104
EST_FMatrix cost_matrix
Definition: dp_main.cc:91
EST_UItem * next()
Definition: EST_UList.h:55
int open(const EST_String &filename)
open a EST_TokenStream for a file.
Definition: EST_Token.cc:213
EST_StrList pattern2_l
Definition: dp_main.cc:84
int eof()
end of file
Definition: EST_Token.h:362
float substitution_cost
Definition: dp_main.cc:97
void set_name(const EST_String &name) const
Definition: EST_Item.h:254
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)
INLINE ssize_t length() const
number of items in vector.
Definition: EST_TVector.h:249
void StringtoStrList(EST_String s, EST_StrList &l, EST_String sep)
Convert a EST_String to a EST_StrList by separating tokens in s delimited by the separator sep...
float local_cost(const EST_Item *s1, const EST_Item *s2)
Definition: dp_main.cc:276
EST_FVector DP_deletion_cost
Definition: dp_main.cc:88
#define FALSE
Definition: EST_bool.h:119
float(* local_cost_function)(const EST_Item *item1, const EST_Item *item2)
Definition: dp_main.cc:52
EST_read_status load(const EST_String &filename)
Load from file (ascii or binary as defined in file)
Definition: EST_FMatrix.cc:523
EST_Token & peek(void)
peek at next token
Definition: EST_Token.h:332
EST_StrList pattern1_l
Definition: dp_main.cc:84
const V & val(const K &rkey, bool m=0) const
return value according to key (const)
Definition: EST_TKVL.cc:145
void append(const T &item)
add item onto end of list
Definition: EST_TList.h:196
int length() const
Definition: EST_UList.cc:57
EST_read_status
EST_IMatrix DP_path_i
Definition: dp_main.cc:90
int main(int argc, char **argv)
Definition: dp_main.cc:108
EST_StrVector pattern1
Definition: dp_main.cc:85
int present(const K &rkey) const
Returns true if key is present.
Definition: EST_TKVL.cc:222
EST_StrVector pattern2
Definition: dp_main.cc:85
EST_UItem * head() const
Definition: EST_UList.h:97
long int StrVector_index(const EST_StrVector &v, const EST_String &s)
Search the vector and return the position of the first occurance of string s in the vector...
bool(* local_pruning_function)(const int i, const int j, const int max_i, const int max_j)
Definition: dp_main.cc:56
EST_Item * append(EST_Item *si)
Definition: EST_Relation.cc:88
EST_StrList vocab_l
Definition: dp_main.cc:84
float deletion_cost
Definition: dp_main.cc:96
EST_String
float insertion_cost
Definition: dp_main.cc:95
#define TRUE
Definition: EST_bool.h:118
EST_String distance_measure
Definition: dp_main.cc:105
int parse_command_line(int argc, char *argv[], const EST_String &usage, EST_StrList &files, EST_Option &al, int make_stdio=1)
Definition: cmd_line.cc:101
#define bool
Definition: EST_bool.h:117
EST_StrVector vocab
Definition: dp_main.cc:85
EST_IMatrix DP_path_j
Definition: dp_main.cc:90
EST_FMatrix DP_substitution_cost
Definition: dp_main.cc:87