Edinburgh Speech Tools  2.4-release
EST_Relation.cc
1 /*************************************************************************/
2 /* */
3 /* Centre for Speech Technology Research */
4 /* University of Edinburgh, UK */
5 /* Copyright (c) 1998 */
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 : February 1998 */
35 /*-----------------------------------------------------------------------*/
36 /* Generalised relations in utterances */
37 /* */
38 /*=======================================================================*/
39 #include <cstdlib>
40 #include <cstdio>
41 #include <iostream>
42 #include <fstream>
43 #include "ling_class/EST_Relation.h"
44 #include "ling_class/EST_Item.h"
45 #include "relation_io.h"
46 
47 VAL_REGISTER_CLASS(relation,EST_Relation)
48 
50 {
51  p_name = name;
52  p_head = 0;
53  p_tail = 0;
54  p_utt = 0;
55 }
56 
58 {
59  p_head = 0;
60  p_tail = 0;
61  p_utt = 0;
62 }
63 
64 void EST_Relation::copy(const EST_Relation &r)
65 {
66  // Do a *full* copy include the contents of all the items
67  // But not the name (?)
68  EST_String tmp_name;
69  p_name = r.p_name;
70  p_head = 0;
71  p_tail = 0;
72  p_utt = 0; // can't be in the same utterance as r
73 
74  tmp_name = f.S("name", "");
75  f = r.f;
76  f.set("name", tmp_name);
77 
78  if (r.root() != 0)
79  {
80  EST_Item i = *r.root();
81  EST_Item *to_root = append(&i);
82  copy_node_tree_contents(r.root(),to_root);
83  }
84 }
85 
86 EST_Item *EST_Relation::append(EST_Item *si)
87 {
88 
89  EST_Item *nn;
90 
91  if (p_tail == 0)
92  {
93  nn = new EST_Item(this, si);
94  p_head = nn;
95  }
96  else
97  nn = p_tail->insert_after(si);
98  p_tail = nn;
99 
100 // if (!si->f_present("id") && utt())
101 // si->fset("id", utt()->next_id());
102 
103  return nn;
104 }
105 
106 EST_Item *EST_Relation::append()
107 {
108  return append(0);
109 }
110 
111 EST_Item *EST_Relation::prepend()
112 {
113  return prepend(0);
114 }
115 
116 EST_Item *EST_Relation::prepend(EST_Item *si)
117 {
118  EST_Item *nn;
119 
120  if (p_head == 0)
121  {
122  nn = new EST_Item(this,si);
123  p_tail = nn;
124  }
125  else
126  nn = p_head->insert_before(si);
127  p_head = nn;
128 
129  return nn;
130 }
131 
133 {
134  clear();
135 }
136 
138 {
139  EST_Item *node;
140  int i;
141 
142  for (i=0,node=p_head; node; node=inext(node))
143  i++;
144  return i;
145 }
146 
148 {
149  for (EST_Item *s = head(); s; s = inext(s))
150  s->evaluate_features();
151 }
152 
154 {
155  EST_Item *nn,*nnn;
156 
157  for (nn = p_head; nn != 0; nn = nnn)
158  {
159  nnn = inext(nn);
160  delete nn;
161  }
162  p_head = p_tail = 0;
163 }
164 
166 {
167  if (p_head == node)
168  p_head = inext(node);
169  if (p_tail == node)
170  p_tail = iprev(node);
171  delete node;
172 }
173 
175 {
176  for (EST_Item *s = p_head; s; s = next_item(s))
177  s->f_remove(name);
178 }
179 
180 void copy_relation(const EST_Relation &from, EST_Relation &to)
181 {
182  // clone the relation structure from into to, deleting any existing
183  // nodes in to.
184 
185  to.clear();
186 
187  if (from.root() != 0)
188  {
189  EST_Item *to_root = to.append(from.root());
190  copy_node_tree(from.root(),to_root);
191  }
192 }
193 
194 EST_write_status EST_Relation::save(ostream &outf,
195  const EST_String &type,
196  bool evaluate_ff) const
197 {
198  if (type == "esps")
199  return save_esps_label(&outf,*this,evaluate_ff);
200  else if (type == "htk")
201  return save_htk_label(&outf,*this);
202  else
203  {
204  EST_warning("EST_Relation: unsupported type: \"%s\"", (const char *)type);
205  return write_fail;
206  }
207 }
208 
209 EST_write_status EST_Relation::save(const EST_String &filename,
210  const EST_String &type,
211  bool evaluate_ff) const
212 {
213  if (type == "esps")
214  return save_esps_label(filename,*this,evaluate_ff);
215  else if (type == "htk")
216  return save_htk_label(filename,*this);
217  else
218  {
219  EST_warning("EST_Relation: unsupported type: \"%s\"", (const char *)type);
220  return write_fail;
221  }
222 }
223 
224 EST_write_status EST_Relation::save(const EST_String &filename,
225  bool evaluate_ff) const
226 {
227  return save(filename,"esps",evaluate_ff);
228 }
229 
230 EST_write_status EST_Relation::save(ostream &outf,
231  EST_TKVL<void *,int> contents) const
232 {
233  EST_TKVL<void *,int> nodenames;
234  int node_count = 1;
235  outf << "Relation " << name() << " ; ";
236  f.save(outf);
237  outf << endl;
238  save_items(p_head,outf,contents,nodenames,node_count);
239  outf << "End_of_Relation" << endl;
240  return write_ok;
241 }
242 
243 EST_write_status EST_Relation::save_items(EST_Item *node,
244  ostream &outf,
245  EST_TKVL<void *,int> &cnames,
246  EST_TKVL<void *,int> &nodenames,
247  int &node_count) const
248 {
249  if (node != 0)
250  {
251  EST_Item *n = node;
252  int myname;
253 
254  while (n)
255  {
256  myname = node_count++;
257  nodenames.add_item(n,myname);
258  n = inext(n);
259  }
260 
261  n = node;
262  while (n)
263  {
264  // This will need to be expanded if the we make Relations
265  // have more complex structures
266  save_items(idown(n),outf,cnames,nodenames,node_count);
267  outf << nodenames.val(n) << " " <<
268  (n->contents() == 0 ? 0 : cnames.val(n->contents())) << " " <<
269  (iup(n) == 0 ? 0 : nodenames.val(iup(n))) << " " <<
270  (idown(n) == 0 ? 0 : nodenames.val(idown(n))) << " " <<
271  (inext(n) == 0 ? 0 : nodenames.val(inext(n))) << " " <<
272  (iprev(n) == 0 ? 0 : nodenames.val(iprev(n))) << endl;
273  n = inext(n);
274  }
275  }
276  return write_ok;
277 }
278 
279 #if 0
280 EST_read_status EST_Relation::load(EST_TokenStream &ts,
281  const EST_THash<int,EST_Val> &contents)
282 {
283  if (ts.get() != "Relation")
284  {
285  cerr << "load_relation: " << ts.pos_description() <<
286  " no new Relation" << endl;
287  return misc_read_error;
288  }
289  p_name = ts.get().string();
290  if (ts.get() != ";")
291  {
292  cerr << "load_relation: " << ts.pos_description() <<
293  " semicolon missing after Relation name \"" <<
294  p_name << "\"" << endl;
295  return misc_read_error;
296  }
297  if (f.load(ts) != format_ok)
298  return misc_read_error;
299  if (load_items(ts,contents) != format_ok)
300  return misc_read_error;
301 
302  return format_ok;
303 }
304 #endif
305 
307  const EST_TVector < EST_Item_Content * > &contents
308  )
309 {
310  if (ts.get() != "Relation")
311  {
312  cerr << "load_relation: " << ts.pos_description() <<
313  " no new Relation" << endl;
314  return misc_read_error;
315  }
316  p_name = ts.get().string();
317  if (ts.get() != ";")
318  {
319  cerr << "load_relation: " << ts.pos_description() <<
320  " semicolon missing after Relation name \"" <<
321  p_name << "\"" << endl;
322  return misc_read_error;
323  }
324  if (f.load(ts) != format_ok)
325  return misc_read_error;
326  if (load_items(ts,contents) != format_ok)
327  return misc_read_error;
328 
329  return format_ok;
330 }
331 
332 void EST_Relation::node_tidy_up_val(int &k, EST_Val &v)
333 {
334  // Called to delete the nodes in the hash table when a load
335  // fails
336  (void)k;
337  EST_Item *node = item(v);
338  node->u = 0;
339  node->d = 0;
340  node->n = 0;
341  node->p = 0;
342  delete node;
343 }
344 
345 void EST_Relation::node_tidy_up(int &k, EST_Item *node)
346 {
347  // Called to delete the nodes in the hash table when a load
348  // fails
349  (void)k;
350  node->u = 0;
351  node->d = 0;
352  node->n = 0;
353  node->p = 0;
354  delete node;
355 }
356 
357 #if 0
358 EST_read_status EST_Relation::load_items(EST_TokenStream &ts,
359  const EST_THash<int,EST_Val> &contents)
360 {
361  // Load a set of nodes from a TokenStream, the file contains node
362  // descriptions one per line as 5 ints, this nodes name, the
363  // stream item it is to be related to, then the name of the
364  // nodes above, below, before and after it.
365  EST_THash<int,EST_Val> nodenames(100);
366  EST_read_status r = format_ok;
367  EST_Item *node = 0;
368  EST_Relation *rel=NULL;
369 // int expect_links=0;
370 
371  while (ts.peek() != "End_of_Relation")
372  {
373  int name = atoi(ts.get().string());
374  int siname;
375 
376  node = get_item_from_name(nodenames,name);
377  if (!node)
378  EST_error("Unknown item %d", name);
379 
380  if (rel==NULL)
381  {
382  rel=node->relation();
383 // EST_String type = rel->f.S("type", "");
384 // expect_links = (type == "ladder");
385  }
386 
387  siname = atoi(ts.get().string());
388  if (siname != 0)
389  {
390  int found;
391  EST_Val v = contents.val(siname,found);
392  if (!found)
393  {
394  cerr << "load_nodes: " << ts.pos_description() <<
395  " node's item contents" << siname << " doesn't exist\n";
396  r = misc_read_error;
397  break;
398  }
399  else
400  node->set_contents(icontent(v));
401  }
402  // up down next previous
403  node->u = get_item_from_name(nodenames,atoi(ts.get().string()));
404  node->d = get_item_from_name(nodenames,atoi(ts.get().string()));
405  node->n = get_item_from_name(nodenames,atoi(ts.get().string()));
406  node->p = get_item_from_name(nodenames,atoi(ts.get().string()));
407 
408 
409  // Read ladder links
410 #if 0
411  if (expect_links)
412  {
413  int numlinks = atoi(ts.get().string());
414  // node->link_feats.set("num_links",numlinks);
415  for (int i=0;i<numlinks;++i)
416  {
417  EST_Item * item = get_item_from_name(nodenames,atoi(ts.get().string()));
418  node->link_feats.set_val("link" + itoString(i),est_val(item));
419  }
420  }
421 #endif
422  }
423 
424  ts.get(); // skip End_of_Relation
425 
426  if (r == format_ok)
427  {
428  if (node != 0) // at least one node
429  {
430  p_head = get_item_from_name(nodenames,1);
431  p_tail = last(p_head);
432  if (!p_head->verify())
433  {
434  cerr << "load_nodes: " << ts.pos_description() <<
435  " nodes do not form consistent graph" << endl;
436  r = misc_read_error;
437  }
438  }
439  }
440 
441  if (r != format_ok)
442  {
443  // failed to read this relation so clear the created nodes
444  // before returning, no idea what state the links are in so
445  // explicitly unlink them before deleting them
446 
447  nodenames.map(node_tidy_up_val);
448  }
449  return r;
450 }
451 #endif
452 
453 EST_read_status EST_Relation::load_items(EST_TokenStream &ts,
454  const EST_TVector < EST_Item_Content * > &contents
455  )
456 {
457  // Load a set of nodes from a TokenStream, the file contains node
458  // descriptions one per line as 5 ints, this nodes name, the
459  // stream item it is to be related to, then the name of the
460  // nodes above, below, before and after it.
461 
462  EST_TVector < EST_Item * > nodenames(100);
463  // EST_THash<int,EST_Val> nodenames(100);
464  EST_read_status r = format_ok;
465  EST_Item *node = 0;
466  EST_Relation *rel=NULL;
467 // int expect_links=0;
468 
469  while (ts.peek() != "End_of_Relation")
470  {
471  int name = atoi(ts.get().string());
472  int siname;
473 
474  node = get_item_from_name(nodenames,name);
475  if (!node)
476  EST_error("Unknown item %d", name);
477 
478  if (rel==NULL)
479  {
480  rel=node->relation();
481 // EST_String type = rel->f.S("type", "");
482 // expect_links = (type == "ladder");
483  }
484 
485  siname = atoi(ts.get().string());
486  if (siname != 0)
487  {
488  EST_Item_Content *c = contents(siname);
489  if (c==NULL)
490  {
491  cerr << "load_nodes: " << ts.pos_description() <<
492  " node's stream item " << siname << " doesn't exist\n";
493  r = misc_read_error;
494  break;
495  }
496  else
497  node->set_contents(c);
498  }
499  // up down next previous
500  node->u = get_item_from_name(nodenames,atoi(ts.get().string()));
501  node->d = get_item_from_name(nodenames,atoi(ts.get().string()));
502  node->n = get_item_from_name(nodenames,atoi(ts.get().string()));
503  node->p = get_item_from_name(nodenames,atoi(ts.get().string()));
504 
505 #if 0
506  // Read ladder links
507  if (expect_links)
508  {
509  int numlinks = atoi(ts.get().string());
510  // node->link_feats.set("num_links",numlinks);
511  for (int i=0;i<numlinks;++i)
512  {
513  EST_Item * item = get_item_from_name(nodenames,atoi(ts.get().string()));
514  // node->link_feats.set_val("link" + itoString(i),est_val(item));
515  }
516  }
517 #endif
518  }
519 
520  ts.get(); // skip End_of_Relation
521 
522  if (r == format_ok)
523  {
524  if (node != 0) // at least one node
525  p_head = get_item_from_name(nodenames,1);
526  if (p_head)
527  p_tail = last(p_head);
528  if (p_head && !p_head->verify())
529  {
530  cerr << "load_nodes: " << ts.pos_description() <<
531  " nodes do not form consistent graph" << endl;
532  r = misc_read_error;
533  }
534  }
535 
536  if (r != format_ok)
537  {
538  // failed to read this relation so clear the created nodes
539  // before returning, no idea what state the links are in so
540  // explicitly unlink them before deleting them
541  for(int ni=0; ni<nodenames.length(); ni++)
542  {
543  EST_Item *node = nodenames(ni);
544  if (node != NULL)
545  node_tidy_up(ni, node);
546  }
547  }
548  return r;
549 }
550 
551 EST_Item *EST_Relation::get_item_from_name(EST_THash<int,EST_Val> &nodenames,
552  int name)
553 {
554  // Return node named by name or create a new one if it doesn't
555  // already exist
556  EST_Item *node;
557  int found;
558 
559  if (name == 0)
560  return 0;
561  EST_Val v = nodenames.val(name,found);
562  if (!found)
563  {
564  node = new EST_Item(this, 0);
565  nodenames.add_item(name,est_val(node));
566  }
567  else
568  node = item(v);
569  return node;
570 }
571 
572 EST_Item *EST_Relation::get_item_from_name(EST_TVector< EST_Item * > &nodenames,
573  int name)
574 {
575  // Return node named by name or create a new one if it doesn't
576  // already exist
577 
578  if (name == 0)
579  return 0;
580 
581  if (name >= nodenames.length())
582  {
583  nodenames.resize(name*2, 1);
584  }
585 
586  EST_Item *node = nodenames(name);
587  if (node==NULL)
588  {
589  node = new EST_Item(this, 0);
590  nodenames[name] = node;
591  }
592 
593  return node;
594 }
595 
596 EST_read_status EST_Relation::load(const EST_String &filename,
597  EST_TokenStream &ts,
598  const EST_String &type)
599 {
600  EST_read_status r;
601 
602  f.set("filename",filename);
603 
604  if (type == "esps")
605  r = load_esps_label(ts,*this);
606  else if (type == "ogi")
607  r = load_ogi_label(ts,*this);
608  else if (type == "htk")
609  r = load_sample_label(ts,*this,10000000);
610  else if ((type == "ascii") || (type == "timit"))
611  r = load_sample_label(ts,*this,1);
612  else if (type == "words")
613  r = load_words_label(ts,*this);
614  else // currently esps is the default
615  r = load_esps_label(ts,*this);
616 
617  return r;
618 }
619 
620 EST_read_status EST_Relation::load(const EST_String &filename,
621  const EST_String &type)
622 {
623  // Load an isolated relation from a file, assuming Xlabel format
624  EST_TokenStream ts;
625  EST_read_status r;
626 
627  if (((filename == "-") ? ts.open(cin) : ts.open(filename)) != 0)
628  {
629  cerr << "load_relation: can't open relation input file "
630  << filename << endl;
631  return misc_read_error;
632  }
633  r = load(filename, ts, type);
634 
635  ts.close();
636 
637  return r;
638 }
639 
640 int num_leaves(const EST_Item *h)
641 {
642  int count = 0;
643  EST_Item *n;
644 
645  for (n = first_leaf(h); n != 0; n=next_leaf(n))
646  count++;
647  return count;
648 }
649 
650 EST_Utterance *get_utt(EST_Item *s)
651 {
652  // Occasionally you need to get the utterance from a stream_item
653  // This finds any relations in s and follows them to the utterance
654  // If there aren't any Relations the this streamitem isn't in an
655  // utterances
656 
657  if (s == 0)
658  return 0;
659  if (s->relation())
660  return s->relation()->utt();
661  else
662  return 0; // can't find an utterance
663 }
664 
665 EST_Relation &EST_Relation::operator=(const EST_Relation &s)
666 {
667  copy(s);
668  return *this;
669 }
670 
671 ostream& operator << (ostream &s, const EST_Relation &a)
672 {
673  s << a.f << endl;
674 
675  for (EST_Item *p = a.head(); p; p = inext(p))
676  s << *p << endl;
677 
678  return s;
679 }
680 
681 
void set(const EST_String &name, int ival)
Definition: EST_Features.h:185
EST_read_status load(EST_TokenStream &ts)
load features from already opened EST_TokenStream
EST_write_status save(ostream &outf) const
save features in already opened ostream
const EST_String S(const EST_String &path) const
Definition: EST_Features.h:157
EST_Relation * relation(void) const
The relation of this particular item.
Definition: EST_Item.h:316
void set_val(const EST_String &name, const EST_Val &sval)
Definition: EST_Item.h:214
void remove_item_feature(const EST_String &name)
const EST_String & name() const
Definition: EST_Relation.h:122
void remove_item(EST_Item *item)
EST_Features f
Definition: EST_Relation.h:103
EST_read_status load(const EST_String &filename, const EST_String &type="esps")
EST_Item * root() const
Definition: EST_Relation.h:128
EST_write_status save(const EST_String &filename, bool evaluate_ff=false) const
int length() const
EST_Utterance * utt(void)
Definition: EST_Relation.h:115
void evaluate_item_features()
EST_Item * head() const
Definition: EST_Relation.h:125
V & val(const K &key, int &found) const
Definition: EST_THash.cc:114
int add_item(const K &key, const V &value, int no_search=0)
Add an entry to the table.
Definition: EST_THash.cc:167
const int length() const
number of key value pairs in list
Definition: EST_TKVL.h:96
int add_item(const K &rkey, const V &rval, int no_search=0)
add key-val pair to list
Definition: EST_TKVL.cc:248
const V & val(const K &rkey, bool m=0) const
return value according to key (const)
Definition: EST_TKVL.cc:145
void map(void(*func)(K &, V &))
apply function to each pair
Definition: EST_TKVL.cc:233
void resize(int n, int set=1)
Definition: EST_TVector.cc:196
INLINE int length() const
number of items in vector.
Definition: EST_TVector.h:252
const EST_String pos_description()
A string describing current position, suitable for error messages.
Definition: EST_Token.cc:875
EST_Token & peek(void)
peek at next token
Definition: EST_Token.cc:830
void close(void)
Close stream.
Definition: EST_Token.cc:406
int open(const EST_String &filename)
open a \Ref{EST_TokenStream} for a file.
Definition: EST_Token.cc:200
EST_TokenStream & get(EST_Token &t)
get next token in stream
Definition: EST_Token.cc:486