Edinburgh Speech Tools 2.4-release
 
Loading...
Searching...
No Matches
ling_example.cc
1/*************************************************************************/
2/* */
3/* Centre for Speech Technology Research */
4/* University of Edinburgh, UK */
5/* Copyright (c) 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
34#include "EST_unix.h"
35#include "EST_ling_class.h"
36
37
38/** @name Linguistic Classes Example Code
39 */
40//@{
41
42int main(void)
43{
44
45 /** @name Adding basic information to an EST_Item
46 *
47 * An item such as
48 * <graphic fileref="../arch_doc/eq01.gif" format="gif"></graphic>
49 * is constructed as follows: (note that
50 * the attributes are in capitals by linguistic convention only:
51 * attribute names are case sensitive and can be upper or lower
52 * case).
53 */
54 //@{
55
56 //@{ code
57 EST_Item p;
58
59 p.set("POS", "Noun");
60 p.set("NAME", "example");
61 p.set("FOCUS", "+");
62 p.set("DURATION", 2.76);
63 p.set("STRESS", 2);
64
65 //@} code
66
67 /** The type of the values in features is a
68 * <classname>EST_Val</classname> class, which is a union which can
69 * store ints, floats, EST_Strings, void pointers, and
70 * <classname>EST_Features</classname>. The overloaded function
71 * facility of C++ means that the <function>set()</function> can be
72 * used for all of these.
73 */
74
75 //@}
76
77 /** @name Accessing basic information in an Item
78 *
79 * When accessing the features, the type must be
80 * specified. This is done most easily by using of a series of
81 * functions whose type is coded by a capital letter:
82 * </para>
83 * <formalpara><title><function>F()</function></title><para> return value as a
84 * float</para></formalpara>
85 * <formalpara><title><function>I()</function></title><para> return value as a
86 * integer</para></formalpara>
87 * <formalpara><title><function>S()</function></title><para> return value as a
88 * <formalpara><title><function>A()</function></title><para> return value as a
89 * EST_Features</para></formalpara>
90 * <para>
91 */
92
93 //@{
94
95 //@{ code
96 cout << "Part of speech for p is " << p.S("POS") << endl;
97 cout << "Duration for p is " << p.F("DURATION") << endl;
98 cout << "Stress value for p is " << p.I("STRESS") << endl;
99 //@} code
100
101 /** </para>
102 * <SIDEBAR>
103 * <TITLE>Output</TITLE>
104 * <screen>
105 * "Noun"
106 * 2.75
107 * 1
108 * </screen>
109 * </SIDEBAR>
110 * <para>
111 * A optional default value can be given if a result is always desired
112 */
113
114 //@{ code
115 cout << "Part of speech for p is "
116 << p.S("POS") << endl;
117 cout << "Syntactic Category for p is "
118 << p.S("CAT", "Noun") << endl; // noerror
119 //@} code
120
121 //@}
122
123 /** @name Nested feature structures in items
124 *
125 * Nested feature structures such as <xref linkend="eq11">
126 * <example ID="eq11">
127 * <title>Example eq11</title>
128 * <graphic fileref="../arch_doc/eq05.gif" format="gif"></graphic>
129 * </example>
130 * can be created in a number of ways:
131 */
132 //@{
133
134 //@{ code
135
136 p.set("NAME", "d");
137 p.set("VOICE", "+");
138 p.set("CONTINUANT", "-");
139 p.set("SONORANT", "-");
140
141 EST_Features f;
142 p.set("PLACE OF ARTICULATION", f); // copy in empty feature set here
143
144 p.A("PLACE OF ARTICULATION").set("CORONAL", "+");
145 p.A("PLACE OF ARTICULATION").set("ANTERIOR", "+");
146 //@} code
147
148 /** or by filling the values in an EST_Features object and
149 * copying it in:
150 */
151
152 //@{ code
153 EST_Features f2;
154
155 f2.set("CORONAL", "+");
156 f2.set("ANTERIOR", "+");
157
158 p.set("PLACE OF ARTICULATION", f2);
159 //@} code
160
161
162 /** Nested features can be accessed by multiple calls to the
163 * accessing commands:
164 */
165
166 //@{ code
167 cout << "Anterior value is: " << p.A("PLACE OF ARTICULATION").S("ANTERIOR");
168 cout << "Coronal value is: " << p.A("PLACE OF ARTICULATION").S("CORONAL");
169 //@} code
170
171 /** The first command is <function>A()</function> because PLACE is a
172 * feature structure, and the second command is
173 * <function>S()</function> because it returns a string (the
174 * value or ANTRIOR or CORONAL). A shorthand is provided to
175 * extract the value in a single statement:
176 */
177
178 //@{ code
179 cout << "Anterior value is: " << p.S("PLACE OF ARTICULATION.ANTERIOR");
180 cout << "Coronal value is: " << p.S("PLACE OF ARTICULATION.CORONAL");
181 //@} code
182
183 /** Again, as the last value to be returned is a string
184 * <function>S()</function> must be used. This shorthand can also be used
185 * to set the features:
186 */
187
188 //@{ code
189
190 p.set("PLACE OF ARTICULATION.CORONAL", "+");
191 p.set("PLACE OF ARTICULATION.ANTERIOR", "+");
192 //@} code
193
194 /** this is the easiest and most commonly used method. */
195
196
197 //@}
198
199 /** @name Utility functions for items
200 *
201 * The presence of a attribute can be checked using
202 * <function>f_present()</function>, which returns true if the
203 * attribute is in the item:
204 */
205 //@{
206
207 //@{ code
208 cout << "This is true: " << p.f_present("PLACE OF ARTICULATION");
209 cout << "This is false: " << p.f_present("MANNER");
210 //@} code
211
212 /** A attribute can be removed by <function>f_remove</function>
213 */
214
215 //@{ code
216 p.f_remove("PLACE OF ARTICULATION");
217 //@} code
218
219 //@}
220
221 /** @name Building a linear list relation
222 * <!-- *** UPDATE *** -->
223 *
224 * It is standard to store the phones for an utterance as a linear list
225 * in a EST_Relation object. Each phone is represented by one
226 * EST_Item, whereas the complete list is stored as a
227 * EST_Relation.
228 * </para><para>
229 * The easiest way to build a linear list is by using the
230 * <function>EST_Relation.append()</function>, which when called
231 * without arguments, makes a new empty EST_Item, adds it onto
232 * the end of the relation and returns a pointer to it. The
233 * information relevant to that phone can then be added to the
234 * returned item.
235 */
236 //@{
237
238 //@{ code
239 EST_Relation phones;
240 EST_Item *a;
241
242 a = phones.append();
243
244 a->set("NAME", "f");
245 a->set("TYPE", "consonant");
246
247 a = phones.append();
248
249 a->set("NAME", "o");
250 a->set("TYPE", "vowel");
251
252 a = phones.append();
253
254 a->set("NAME", "r");
255 a->set("TYPE", "consonant");
256 //@} code
257
258 /** Note that the -> operator is used because the EST_Item a is a
259 * pointer here. The same pointer variable can be used multiple
260 * times because every time <function>append()</function> is
261 * called it allocates a new item and returns a pointer to it.
262 * </para><para>
263 * If you already have a EST_Item pointer and want to add it to a
264 * relation, you can give it as an argument to
265 * <function>append()</function>, but this is generally
266 * inadvisable as it involves some unnecessary copying, and also
267 * you have to allocate the memory for the next EST_Item pointer
268 * yourself every time (if you don't you will overwrite the
269 * previous one):
270 */
271
272 //@{ code
273 a = new EST_Item;
274 a->set("NAME", "m");
275 a->set("TYPE", "consonant");
276
277 phones.append(a);
278
279 a = new EST_Item;
280 a->set("NAME", "ei");
281 a->set("TYPE", "vowel");
282 //@} code
283
284 /** Items can be prepended in exactly the same way:
285 */
286 //@{ code
287
288 a = phones.prepend();
289
290 a->set("NAME", "n");
291 a->set("TYPE", "consonant");
292
293 a = phones.prepend();
294
295 a->set("NAME", "i");
296 a->set("TYPE", "vowel");
297
298 //@} code
299
300 //@}
301
302
303 /** @name Iterating through a linear list relation
304 * Iteration in lists is performed with
305 * <function>next()</function> and <function>prev()</function>, and
306 * an EST_Item, used as an iteration pointer.
307 */
308 //@{
309
310 //@{ code
311 EST_Item *s;
312
313 for (s = phones.head(); s != 0; s = inext(s))
314 cout << s->S("NAME") << endl;
315 //@} code
316
317 /** </para>
318 * <SIDEBAR>
319 * <TITLE>Output</TITLE>
320 * <screen>
321 * name:i type:vowel
322 * name:n type:consonant
323 * name:f type:consonant
324 * name:o type:vowel
325 * name:r type:consonant
326 * name:m type:consonant
327 * </screen>
328 * </SIDEBAR>
329 * <para>
330 */
331 //@{ code
332
333 for (s = phones.tail(); s != 0; s = iprev(s))
334 cout << s->S("NAME") << endl;
335
336 //@} code
337
338 /** </para>
339 * <SIDEBAR>
340 * <TITLE>Output</TITLE>
341 * <screen>
342 * name:m type:consonant
343 * name:r type:consonant
344 * name:o type:vowel
345 * name:f type:consonant
346 * name:n type:consonant
347 * name:i type:vowel
348 * </screen>
349 * </SIDEBAR>
350 *
351 *<para>
352 * <function>head()</function> and <function>tail()</function>
353 * return EST_Item pointers to the start and end of the list.
354 * <function>next()</function> and <function>prev()</function>
355 * returns the next or previous item in the list, and returns
356 * <literal>0</literal> when the end or start of the list is
357 * reached. Hence checking for <literal>0</literal> is a useful
358 * termination condition of the iteration. Taking advantage of C
359 * shorthand allows us to write:
360 */
361
362 //@{ code
363 for (s = phones.head(); s; s = inext(s))
364 cout << s->S("NAME") << endl;
365 //@} code
366
367 //@}
368
369 /** @name Building a tree relation
370 *
371 * <!-- *** UPDATE *** -->
372 *
373 * It is standard to store information such as syntax as a tree
374 * in a EST_Relation object. Each tree node is represented by one
375 * EST_Item, whereas the complete tree is stored as a
376 * EST_Relation.
377 * </para><para>
378 * The easiest way to build a tree is by using the
379 * <function>append_daughter()</function>, which when called
380 * without arguments, makes a new empty EST_Item, adds it as a
381 * daughter to an existing item and returns a pointer to it. The
382 * information relevant to that node can then be added to the
383 * returned item. The root node of the tree must be added
384 * directly to the EST_Relation.
385 */
386 //@{
387
388 //@{ code
389 //@example prog01
390 EST_Relation tree;
391 EST_Item *r, *np, *vp, *n;
392
393 r = tree.append();
394 r->set("CAT", "S");
395
396 np = append_daughter(r);
397 np->set("CAT", "NP");
398
399 n = append_daughter(np);
400 n->set("CAT", "PRO");
401
402 n = append_daughter(n);
403 n->set("NAME", "John");
404
405 vp = append_daughter(r);
406 vp->set("CAT", "VP");
407
408 n = append_daughter(vp);
409 n->set("CAT", "VERB");
410 n = append_daughter(n);
411 n->set("NAME", "loves");
412
413 np = append_daughter(vp);
414 np->set("CAT", "NP");
415
416 n = append_daughter(np);
417 n->set("CAT", "DET");
418 n = append_daughter(n);
419 n->set("NAME", "the");
420
421 n = append_daughter(np);
422 n->set("CAT", "NOUN");
423 n = append_daughter(n);
424 n->set("NAME", "woman");
425
426 cout << tree;
427 //@} code
428
429 /** </para>
430 * <SIDEBAR>
431 * <TITLE>Output</TITLE>
432 * <screen>
433 * (S
434 * (NP
435 * (N (John))
436 * )
437 * (VP
438 * (V (loves))
439 * (NP
440 * (DET the)
441 * (NOUN woman))
442 * )
443 *)
444 *</screen>
445 * </SIDEBAR>
446 * <para>
447 * Obviously, the use of recursive functions in building trees is more
448 * efficient and would eliminate the need for the large number of
449 * temporary variables used in the above example.
450 */
451 //@}
452
453 /** @name Iterating through a tree relation
454 *
455 * Iteration in trees is done with <function>daughter1()</function>
456 * <function>daughter2()</function> <function>daughtern()</function> and
457 * <function>parent()</function>. Pre-order traversal can be achieved
458 * iteratively as follows:
459 */
460 //@{
461
462 //@{ code
463 n = tree.head(); // initialise iteration variable to head of tree
464 while (n)
465 {
466 if (daughter1(n) != 0) // if daughter exists, make n its daughter
467 n = daughter1(n);
468 else if (inext(n) != 0)//otherwise visit its sisters
469 n = inext(n);
470 else // if no sisters are left, go back up the tree
471 { // until a sister to a parent is found
472 bool found=FALSE;
473 for (EST_Item *pp = parent(n); pp != 0; pp = parent(pp))
474 if (inext(pp))
475 {
476 n = inext(pp);
477 found=TRUE;
478 break;
479 }
480 if (!found)
481 {
482 n = 0;
483 break;
484 }
485 }
486 cout << *n;
487 }
488 //@} code
489
490 /** A special set of iterators are available for traversal of the leaf
491 * (terminal) nodes of a tree:
492 */
493
494 //@{ code
495 //@ example prog02
496 //@ title Leaf iteration
497
498 for (s = first_leaf(tree.head()); s != last_leaf(tree.head());
499 s = next_leaf(s))
500 cout << s->S("NAME") << endl;
501 //@} code
502
503 //@}
504
505 /** @name Building a multi-linear relation
506 */
507 //@{
508
509 //@}
510
511 /** @name Iterating through a multi-linear relation
512 */
513 //@{
514
515 //@}
516
517 /** @name Relations in Utterances
518 *
519 * The <classname>EST_Utterance</classname> class is used to store all
520 * the items and relations relevant to a single utterance. (Here
521 * utterance is used as a general linguistic entity - it doesn't have to
522 * relate to a well formed complete linguistic unit such as a sentence or
523 * phrase).
524 * </para><para>
525 * Instead of storing relations separately, they are stored in
526 * utterances:
527 */
528 //@{
529
530 //@{ code
531 EST_Utterance utt;
532
533 utt.create_relation("Word");
534 utt.create_relation("Syntax");
535 //@} code
536
537 /** EST_Relations can be accessed though the utterance object either
538 * directly or by use of a temporary EST_Relation pointer:
539 */
540
541 //@{ code
542 EST_Relation *word, *syntax;
543
544 word = utt.relation("Word");
545 syntax = utt.relation("Syntax");
546 //@} code
547
548 /** The contents of the relation can be filled by the methods described
549 * above.
550 */
551
552 //@}
553
554 /** @name Adding items into multiple relations
555 *
556 * A major aspect of this system is that an item can be in two relations
557 * at once, as shown in <xref linkend="figure02">.
558 * </para><para>
559 * In the following example, using the syntax relation as already created
560 * in <xref linkend="prog01">,
561 * shows how to put the terminal nodes of this
562 * tree into a word relation:
563 */
564 //@{
565
566 //@{ code
567 //@example prog03
568 //@title adding existing items to a new relation
569 word = utt.relation("Word");
570 syntax = utt.relation("Syntax");
571
572 for (s = first_leaf(syntax->head()); s != last_leaf(syntax->head());
573 s = next_leaf(s))
574 word->append(s);
575
576 //@} code
577
578 /**
579 * Thus the terminal nodes in the syntax relation are now stored as a
580 * linear list in the word relation.
581 *
582 * Hence
583 */
584
585 //@{ code
586 cout << *utt.relation("Syntax") << "\n";
587 //@} code
588
589 /** produces
590 *</para>
591 * <sidebar>
592 * <title>Output</title>
593 * <screen>
594 *(S
595 * (NP
596 * (N (John))
597 * )
598 * (VP
599 * (V (loves))
600 * (NP
601 * (DET the)
602 * (NOUN woman))
603 * )
604 *)
605 *</screen>
606 *</sidebar>
607 *<para>
608 *whereas
609 */
610
611 //@{ code
612 cout << *utt.relation("Word") << "\n";
613 //@} code
614
615 /** produces
616 *</para>
617 * <sidebar>
618 * <title>Output</title>
619 * <screen>
620 *John
621 *loves
622 *the
623 *woman
624 *</screen>
625 * </sidebar>
626 * <para>
627 */
628
629 //@}
630
631
632 /** @name Changing the relation an item is in
633 as_relation, in relation etc
634 */
635 //@{
636
637 //@}
638
639 /** @name Feature functions
640 evaluate functions
641 setting functions
642 */
643 //@{
644
645
646 //@}
647
648 exit(0);
649
650}
651//@}
void set(const EST_String &name, int ival)
const EST_String S(const EST_String &path) const
const int I(const EST_String &name) const
Definition EST_Item.h:154
void set(const EST_String &name, int ival)
Definition EST_Item.h:179
const EST_String S(const EST_String &name) const
Definition EST_Item.h:143
EST_Features & A(const EST_String &name) const
Definition EST_Item.h:163
const float F(const EST_String &name) const
Definition EST_Item.h:134
void f_remove(const EST_String &name)
Definition EST_Item.h:222
int f_present(const EST_String &name) const
Definition EST_Item.h:230
EST_Item * head() const
EST_Item * tail() const
EST_Relation * relation(const char *name, int err_on_not_found=1) const
get relation by name
EST_Relation * create_relation(const EST_String &relname)
create a new relation called <parameter>n</parameter>.