/*************************************************************************/ /* Copyright (c) 2012, 2013 Linas Vepstas */ /* All rights reserved */ /* */ /* Use of the Viterbi parsing system is subject to the terms of the */ /* license set forth in the LICENSE file included with this software. */ /* This license allows free redistribution and use in source and binary */ /* forms, with or without modification, subject to certain conditions. */ /* */ /*************************************************************************/ #include "compile.h" // XXX temporary hack until dynamic types are supported !? namespace atombase { using namespace link_grammar::viterbi; // ============================================================ /// Remove optional connectors. /// /// It doesn't make any sense at all to have an optional connector /// in an AND-clause, so just remove it. (Well, OK, it "makes sense", /// its just effectively a no-op, and so doesn't have any effect. So, /// removing it here simplifies logic in other places.) /// /// The cost of the optional is passed up to the dsjunct. The reason for /// this is that the doctionary contains entries such as /// , whcih has (Xc+ or ) & MX- /// After being disjoined, we need to pass that cost up. Atom* And::clean() const { TV tv = _tv; OutList cl; size_t sz = get_arity(); // Special case: it could be a and-clause containing a single, // optional connector, in which case, we flatten the thing // (returning the optional connector!) if (1 == sz) { Atom* a = get_outgoing_atom(0); a->_tv += _tv; return a; } for (size_t i=0; i(get_outgoing_atom(i)); if (cn and cn->is_optional()) { tv += cn->_tv; continue; } cl.push_back(_oset[i]); } return new And(cl, tv); } // ============================================================ Atom* Atom::upcaster() { if (!this) return this; const Node* n = dynamic_cast(this); const Link* l = dynamic_cast(this); switch (get_type()) { // Links case AND: if (dynamic_cast(this)) return this; return new And(l->get_outgoing_set(), _tv); case OR: if (dynamic_cast(this)) return this; return new Or(l->get_outgoing_set(), _tv); case SEQ: if (dynamic_cast(this)) return this; return new Seq(l->get_outgoing_set(), _tv); case SET: if (dynamic_cast(this)) return this; return new Set(l->get_outgoing_set(), _tv); // Nodes case CONNECTOR: if (dynamic_cast(this)) return this; return new Connector(n->get_name(), _tv); case WORD: if (dynamic_cast(this)) return this; return new Word(n->get_name(), _tv); default: assert(0, "Atom::upcaster(): implement me!"); } } // ============================================================ Link* Link::append(Atom* a) const { OutList ol = get_outgoing_set(); ol.push_back(a); switch (get_type()) { // Links case AND: return new And(ol, _tv); case OR: return new Or(ol, _tv); case SEQ: return new Seq(ol, _tv); case SET: return new Set(ol, _tv); default: assert(0, "append: implement me!"); } } } // namespace atombase // ============================================================ namespace link_grammar { namespace viterbi { // Helper function for below. static bool has_lefties(Atom* a) { Connector* c = dynamic_cast(a); if (c) { if ('-' == c->get_direction()) return true; return false; } // Verify we've got a valid disjunct AtomType at = a->get_type(); assert ((at == OR) or (at == AND), "Disjunct, expecting OR or AND"); // Recurse down into disjunct Link* l = dynamic_cast(a); size_t sz = l->get_arity(); for (size_t i=0; iget_outgoing_atom(i))) return true; } return false; } /// Return true if any of the connectors in the cset point to the left. bool WordCset::has_left_pointers() const { return has_lefties(get_cset()); } /// Simplify any gratuituousnesting in the cset. WordCset* WordCset::flatten() { // AND and OR inherit from Set Set* s = dynamic_cast(get_cset()); if (NULL == s) return this; Atom* flat = s->super_flatten(); // If there is nothing left after flattening, return NULL. const Link* fl = dynamic_cast(flat); if (fl && 0 == fl->get_arity()) return NULL; return new WordCset(get_word(), flat); } } // namespace viterbi } // namespace link-grammar