Package synalp.commons.grammar

Source Code of synalp.commons.grammar.Tree

package synalp.commons.grammar;

import java.util.*;

import synalp.commons.derivations.GornAddress;
import synalp.commons.input.Lemma;
import synalp.commons.unification.*;


/**
* A Tree.
*/
public class Tree implements UnifiableComponent
{
  private String id;
  private Node root;


  /**
   * Creates a new empty tree with given id.
   * @param id
   */
  public Tree(String id)
  {
    this.id = id;
  }


  /**
   * Creates a new tree with given id and root.
   * @param id
   * @param root
   */
  public Tree(String id, Node root)
  {
    this.id = id;
    this.root = root;
  }


  /**
   * Deep copies the given Tree.
   * @param tree
   */
  public Tree(Tree tree)
  {
    this.id = tree.getId();
    this.root = new Node(tree.getRoot(), null);
  }


  /**
   * Makes sure that all the leaves of this Tree have a lemma anchor. If there is no lemma, create
   * one whose surface form is the node category (first one if many).
   */
  public void lemmatizeLeaves()
  {
    for(Node node : getYield())
      if (node.getAnchorLemma() == null)
      {
        Lemma anchor = new Lemma(node.getCategory().getFirstValue());
        FeatureStructure fs = new FeatureStructure();
        anchor.setFs(fs);
        anchor.setCategory(node.getCategory());
        node.setAnchorLemma(anchor);
      }
  }


  /**
   * Makes sure that all the lemmas of this Tree have a correct feature structure.
   * @param context the context in which to unify the top/bot fs before setting the lemma fs
   */
  public void setupLemmaFeatures(InstantiationContext context)
  {
    for(Node node : getLemmasNodes())
      node.setupLemmaFeatures(context);
  }


  /**
   * Tests if all nodes of this Tree have top and bot fs that unify in the given context.
   * @param context
   * @return true if it is the case, false otherwise
   */
  public boolean topBotUnifies(InstantiationContext context)
  {
    return getFailedTopBotNode(context) == null;
  }


  /**
   * Returns the first found Node of this Tree for which the structures top and bot do not unify
   * in the given context.
   * @param context
   * @return a Node whose top bot unification failed or null if none can be found
   */
  public Node getFailedTopBotNode(InstantiationContext context)
  {
    for(Node node : getNodes())
      if (Unifier.unify(node.getFsTop(), node.getFsBot(), context) == null)
        return node;
    return null;
  }


  /**
   * Replaces the given variable by the given value everywhere it appears in this Tree.
   * @param variable
   * @param value
   */
  @Override
  public void replaceVariable(FeatureVariable variable, FeatureValue value)
  {
    for(Node node : getNodes())
    {
      node.getFsTop().replaceVariable(variable, value);
      node.getFsBot().replaceVariable(variable, value);
    }
  }


  /**
   * Returns all variables that are defined in all feature structures of this Tree.
   * @return a set of variables
   */
  @Override
  public Set<FeatureVariable> getAllVariables()
  {
    Set<FeatureVariable> ret = new HashSet<FeatureVariable>();
    for(Node node : getNodes())
    {
      ret.addAll(node.getFsTop().getAllVariables());
      ret.addAll(node.getFsBot().getAllVariables());
    }
    return ret;
  }


  /**
   * This method has been added for coherence reason. I do not think it will be of practical use.
   */
  @Override
  public void instantiate(InstantiationContext context)
  {
    for(FeatureVariable var : getAllVariables())
      if (context.containsKey(var))
        replaceVariable(var, context.get(var));
  }


  /**
   * Returns the list of lemmas of anchor nodes. Note that this has been changed since we now
   * allow NADJ nodes.
   * @return a list of lemmas
   */
  public List<Lemma> getLemmas()
  {
    List<Lemma> ret = new ArrayList<Lemma>();
    for(Node anchor : getLemmasNodes())
      ret.add(anchor.getAnchorLemma());
    return ret;
  }


  /**
   * Returns the first found main anchor node of this Tree.
   * @return the anchor node
   */
  public Node getMainAnchor()
  {
    return getNodeByType(root, NodeType.ANCHOR);
  }


  /**
   * Returns all anchor nodes of this Tree, including co-anchors.
   * @return the list of anchors and co-anchors in prefix order.
   */
  public List<Node> getAnchors()
  {
    return getNodesByType(root, NodeType.ANCHOR, NodeType.COANCHOR);
  }
 
 
  /**
   * Returns all coanchor nodes of this Tree.
   * @return the list of co-anchors in prefix order.
   */
  public List<Node> getCoAnchors()
  {
    return getNodesByType(root, NodeType.COANCHOR);
  }


  /**
   * Returns all the nodes in prefix order, whatever their type, that contain a non-null lemma.
   * @return the list of nodes whose lemma is not null in prefix order.
   */
  public List<Node> getLemmasNodes()
  {
    List<Node> ret = new ArrayList<Node>();
    for(Node node : getNodes())
      if (node.getAnchorLemma() != null)
        ret.add(node);
    return ret;
  }


  /**
   * Returns all co-anchor nodes of this Tree whose lemma is not yet defined.
   * @return a list of nodes
   */
  public List<Node> getUninstantiatedCoanchors()
  {
    List<Node> ret = new ArrayList<Node>();
    for(Node node : getNodes())
      if (node.getType() == NodeType.COANCHOR && node.getAnchorLemma() == null)
        ret.add(node);
    return ret;
  }


  /**
   * Returns the foot node of this Tree if there is one.
   * @return the foot node or null if there is none
   */
  public Node getFoot()
  {
    return getNodeByType(root, NodeType.FOOT);
  }


  /**
   * Returns all the substitution nodes of this Tree.
   * @return the foot node
   */
  public List<Node> getSubstitutions()
  {
    return getNodesByType(root, NodeType.SUBST);
  }


  /**
   * Returns all the nodes of this Tree in prefix order.
   * @return all the nodes
   */
  public List<Node> getNodes()
  {
    return getNodes(root);
  }


  /**
   * Returns the first found Node with given id. This typically could be cached.
   * @param id
   * @return a Node of this Tree or null if none is found
   */
  public Node getNodeById(String id)
  {
    for(Node node : getNodes())
      if (node.getId().equals(id))
        return node;
    return null;
  }


  /**
   * Returns all the nodes below the given node including the given node.
   * @param node
   * @return a list of nodes
   */
  private List<Node> getNodes(Node node)
  {
    List<Node> ret = new ArrayList<Node>();
    ret.add(node);
    for(Node child : node.getChildren())
      ret.addAll(getNodes(child));
    return ret;
  }


  /**
   * Returns the first found node of this Tree, including root, which has one of the given types.
   * We may consider caching this.
   * @param types
   * @return a Node of this Tree or null if none is found.
   */
  public Node getNodeByType(NodeType... types)
  {
    return getNodeByType(root, types);
  }


  /**
   * Returns all nodes of this Tree in the prefix order, including root, which have one the given
   * types. We may consider caching this.
   * @param types
   * @return a list of Nodes of this Tree or empty list if none is found.
   */
  public List<Node> getNodesByType(NodeType... types)
  {
    return getNodesByType(root, types);
  }


  /**
   * Returns the first found descendant node of the given node, including given node, which has
   * one of the given types. We may consider caching this.
   * @param node
   * @param types
   * @return a Node of this Tree or null if none is found.
   */
  private Node getNodeByType(Node node, NodeType... types)
  {
    for(NodeType type : types)
      if (node.getType() == type)
        return node;

    for(Node child : node.getChildren())
    {
      Node result = getNodeByType(child, types);
      if (result != null)
        return result;
    }

    return null;
  }


  /**
   * Returns all the descendant nodes of the given node in the prefix order, including given node,
   * which have one the given types. We may consider caching this.
   * @param node
   * @param types
   * @return a list of Nodes of this Tree or empty list if none is found.
   */
  private List<Node> getNodesByType(Node node, NodeType... types)
  {
    List<Node> ret = new ArrayList<Node>();
    for(NodeType type : types)
      if (node.getType() == type)
        ret.add(node);
    for(Node child : node.getChildren())
      ret.addAll(getNodesByType(child, types));
    return ret;
  }


  /**
   * Returns the yield of this Tree that is the list of leaves.
   * @return the list of leaves of this Tree
   */
  public List<Node> getYield()
  {
    return getYield(root);
  }


  /**
   * Returns the yield of a Node, that is the list of leaves.
   * @param node
   * @return the list of leaves accessible from the given Node
   */
  private List<Node> getYield(Node node)
  {
    List<Node> ret = new ArrayList<Node>();
    if (node.getChildren().isEmpty())
      ret.add(node);
    else for(Node child : node.getChildren())
      ret.addAll(getYield(child));
    return ret;
  }


  /**
   * Returns the Node of this Tree referred to by given address.
   * @param address
   * @return a Node of this Tree or null if the address is out of bounds
   */
  public Node getNode(GornAddress address)
  {
    return address.getNode(this);
  }


  /**
   * @return the name
   */
  public String getId()
  {
    return id;
  }


  /**
   * @param id the name to set
   */
  public void setId(String id)
  {
    this.id = id;
  }


  /**
   * @return the root of the tree
   */
  public final Node getRoot()
  {
    return root;
  }


  /**
   * @param root
   */
  public void setRoot(Node root)
  {
    this.root = root;
  }


  /**
   * Tests if this Tree is auxiliary. This typically could be cached.
   * @return whether the Tree contains a foot node
   */
  public boolean isAuxiliary()
  {
    return getFoot() != null;
  }


  /**
   * Returns a pretty representation of the tree. Note that it uses unicode characters to
   * represent the node types.
   * @return a String
   */
  @Override
  public String toString()
  {
    return toString(new InstantiationContext());
  }


  /**
   * Returns a pretty representation of the tree. Note that it uses unicode characters to
   * represent the node types.
   * @param context
   * @return a String
   */
  public String toString(InstantiationContext context)
  {
    return toString(NodeFormat.MINIMALIST, context);
  }


  /**
   * Returns a pretty representation of the tree. Note that it uses unicode characters to
   * represent the node types.
   * @param format
   * @param context
   * @return a String
   */
  public String toString(NodeFormat format, InstantiationContext context)
  {
    return root.toString(format, context);
  }


  /**
   * Only uses the id.
   */
  @Override
  public int hashCode()
  {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((id == null) ? 0 : id.hashCode());
    return result;
  }


  /**
   * Only uses the id.
   */
  @Override
  public boolean equals(Object obj)
  {
    if (this == obj)
      return true;
    if (obj == null)
      return false;
    if (getClass() != obj.getClass())
      return false;
    Tree other = (Tree) obj;
    if (id == null)
    {
      if (other.id != null)
        return false;
    }
    else if (!id.equals(other.id))
      return false;
    return true;
  }

}
TOP

Related Classes of synalp.commons.grammar.Tree

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.