/* Copyright (C) 2003 Univ. of Massachusetts Amherst, Computer Science Dept. This file is part of "MALLET" (MAchine Learning for LanguagE Toolkit). http://www.cs.umass.edu/~mccallum/mallet This software is provided under the terms of the Common Public License, version 1.0, as published by http://www.opensource.org. For further information, see the file `LICENSE' included with this distribution. */ package cc.mallet.grmm.types; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import cc.mallet.types.Alphabet; import gnu.trove.TObjectIntHashMap; /** * Class for arbitrary trees, based on implementation in OpenJGraph. * The OpenJGraph tree implementation is a bit minimal wrt * convenience functions, so we add a few here. * * Created: Wed Oct 1 14:51:47 2003 * * @author <a href="mailto:casutton@cs.umass.edu">Charles Sutton</a> * @version $Id: Tree.java,v 1.1 2007/10/22 21:37:44 mccallum Exp $ */ public class Tree { private TObjectIntHashMap vertex2int = new TObjectIntHashMap (); private ArrayList int2vertex = new ArrayList (); private ArrayList parents = new ArrayList (); private ArrayList children = new ArrayList (); private Object root = null; public Tree() {} // Tree constructor // Efficient indexing of parents, children public static Tree makeFromSubtree (Object parent, List subtrees) { Tree tree = new Tree(); tree.add (parent); for (Iterator it = subtrees.iterator (); it.hasNext ();) { Tree subtree = (Tree) it.next (); tree.addSubtree (parent, subtree, subtree.getRoot ()); } return tree; } private void addSubtree (Object parent, Tree subtree, Object child) { addNode (parent, child); for (Iterator it = subtree.getChildren (child).iterator (); it.hasNext ();) { Object gchild = it.next (); addSubtree (child, subtree, gchild); } } protected int lookupIndex (Object v) { return vertex2int.get (v); } protected Object lookupVertex (int idx) { return int2vertex.get (idx); } int maybeAddVertex (Object v) { if (!vertex2int.containsKey (v)) { int foo = int2vertex.size (); int2vertex.add (v); vertex2int.put (v, foo); parents.add (null); children.add (new ArrayList ()); return foo; } else { return vertex2int.get (v); } } public void add (Object rt) { if (root == null) { maybeAddVertex (rt); root = rt; } else { throw new UnsupportedOperationException ("This tree already has a root."); } } public void addNode (Object parent, Object child) { int id1; if (root == null) { root = parent; id1 = maybeAddVertex (parent); } else if ((id1 = lookupIndex (parent)) == -1) throw new UnsupportedOperationException ("This tree already has a root."); int id2 = maybeAddVertex (child); Object oldParent = parents.get (id2); if ((oldParent != null) && (oldParent != parent)) throw new UnsupportedOperationException ("Trying to change parent of Object "+child+" from " +oldParent+" to "+parent); parents.set (id2, parent); ArrayList childList = (ArrayList) children.get (id1); childList.add (child); } public Object getParent (Object child) { if (vertex2int.containsKey (child)) { return parents.get (vertex2int.get (child)); } else { return null; } } public List getChildren (Object parent) { int id = vertex2int.get (parent); return Collections.unmodifiableList ((List) children.get (id)); } // Convenience functions public boolean isRoot (Object var) { int idx = lookupIndex (var); return (parents.get(idx) == null); } public boolean containsObject (Object v) { return (vertex2int.get (v) >= 0); } public boolean isLeaf (Object v) { int idx = lookupIndex (v); return ((List)children.get(idx)).size() == 0; } public Iterator getVerticesIterator () { return int2vertex.iterator(); } public Object getRoot () { return root; } public String dumpToString () { StringBuffer buf = new StringBuffer (); dumpRec (root, 0, buf); return buf.toString (); } private void dumpRec (Object node, int lvl, StringBuffer buf) { for (int i = 0; i < 3 * lvl; i++) { buf.append ("-"); } buf.append (" ").append (node).append ("\n"); for (Iterator it = getChildren (node).iterator (); it.hasNext();) { Object child = it.next (); dumpRec (child, lvl+1, buf); } } } // Tree