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