"Fossies" - the Fresh Open Source Software Archive 
Member "speech_tools/ling_class/EST_Relation.cc" (4 Sep 2017, 17698 Bytes) of package /linux/misc/speech_tools-2.5.0-release.tar.gz:
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
49 EST_Relation::EST_Relation(const EST_String &name)
50 {
51 p_name = name;
52 p_head = 0;
53 p_tail = 0;
54 p_utt = 0;
55 }
56
57 EST_Relation::EST_Relation()
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
132 EST_Relation::~EST_Relation()
133 {
134 clear();
135 }
136
137 int EST_Relation::length() const
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
147 void EST_Relation::evaluate_item_features()
148 {
149 for (EST_Item *s = head(); s; s = inext(s))
150 s->evaluate_features();
151 }
152
153 void EST_Relation::clear()
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
165 void EST_Relation::remove_item(EST_Item *node)
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
174 void EST_Relation::remove_item_feature(const EST_String &name)
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
306 EST_read_status EST_Relation::load(EST_TokenStream &ts,
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