Edinburgh Speech Tools  2.4-release
 All Classes Functions Variables Typedefs Enumerations Enumerator Friends Pages
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 
42 int 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 = s->next())
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 = s->prev())
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 = s->next())
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 (n->next() != 0)//otherwise visit its sisters
469  n = n->next();
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 (pp->next())
475  {
476  n = pp->next();
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 //@}