"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:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "EST_Relation.cc" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.4-release_vs_2.5.0-release.

    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