/* This file is part of the Joshua Machine Translation System. * * Joshua is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 * of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ package joshua.ui.tree_visualizer; import java.util.Scanner; import java.util.LinkedList; import edu.uci.ics.jung.graph.DirectedOrderedSparseMultigraph; import java.awt.Color; import java.io.File; import java.io.FileNotFoundException; import javax.swing.JFrame; import javax.swing.WindowConstants; import joshua.util.Regex; public class DerivationTree extends DirectedOrderedSparseMultigraph<Node,DerivationTreeEdge> { /** * Eclipse thinks this is necessary. */ private static final long serialVersionUID = 2914449263979566324L; // man are java regexes ugly // field seperator for joshua output public static final String DELIMITER = "\\|\\|\\|"; public static final String SPACE = "\\s+"; public static final int TGT_LINE = 1; public static final int SRC_LINE = 1; private Node root; private Node sourceRoot; private String source; private LinkedList<Node> vertices; Node picked; public static void main(String [] argv) { try { int line = 1; Scanner tgt = new Scanner(new File(argv[0]), "UTF-8"); DerivationTree g; while (line < TGT_LINE) { tgt.nextLine(); line++; } if (argv.length > 1) { Scanner src = new Scanner(new File(argv[1]), "UTF-8"); int srcLine = 1; while (srcLine < SRC_LINE) { src.nextLine(); srcLine++; } g = new DerivationTree(tgt.nextLine().split(DELIMITER)[1], src.nextLine()); } else { g = new DerivationTree(tgt.nextLine().split(DELIMITER)[1]); } JFrame frame = new JFrame("derivation tree"); DerivationViewer viewer = new DerivationViewer(g, frame.getSize(), Color.red, DerivationViewer.AnchorType.ANCHOR_LEFTMOST_LEAF); frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); frame.setSize(500, 500); frame.getContentPane().add(viewer); frame.pack(); frame.setVisible(true); } catch (FileNotFoundException e) { System.err.println(e.getMessage()); } return; } public DerivationTree(String tree) { super(); vertices = new LinkedList<Node>(); graph(tree); } public DerivationTree(String tree, String source) { super(); vertices = new LinkedList<Node>(); this.source = source; graph(tree); } public Node getRoot() { return root; } public Node getSourceRoot() { return sourceRoot; } private void graph(String tree) { String [] toks = tree.replaceAll("\\)", "\n)").split(SPACE); treeToGraph(toks, null, 0); if (source != null) { addSourceNodes(root, null, 0); } return; } private int treeToGraph(String [] toks, Node parent, int curr) { String child = null; while (curr < toks.length) { String head = toks[curr]; while (head.equals("")) { curr++; head = toks[curr]; } curr++; if (head.equals(")")) { addVertexWithContext(child, parent, false); return curr; } if (head.startsWith("(")) { if (child != null) { addVertexWithContext(child, parent, false); } child = null; String nodeStr = head.substring(1); Node node = addVertexWithContext(nodeStr, parent, false); curr = treeToGraph(toks, node, curr); } else { if (child == null) { child = head; } else { child += " " + head; } } } return curr; } private Node addVertexWithContext(String child, Node parent, boolean isSource) { Node childNode; if (child == null) return null; if (parent != null) { if (source != null) { childNode = new Node(child, parent, isSource); } else { childNode = new Node(child, isSource); } addEdge(new DerivationTreeEdge(false), parent, childNode); } else { childNode = new Node(child, isSource); addVertex(childNode); if (isSource) sourceRoot = childNode; else root = childNode; } if (!isSource) vertices.add(childNode); return childNode; } private int addSourceNodes(Node curr, Node parent, int currentSourceIndex) { if (getSuccessors(curr).isEmpty()) return currentSourceIndex; LinkedList<Node> children = new LinkedList<Node>(getSuccessors(curr)); Node currSource = addVertexWithContext(curr.toString(), parent, true); currSource.setSourceSpan(curr.sourceStart(), curr.sourceEnd()); while (!children.isEmpty()) { Node leftMost = children.get(0); for (Node n : children) { if (n.sourceStart() < leftMost.sourceStart()) leftMost = n; } if (leftMost.sourceStart() > currentSourceIndex) { String [] sourceTokens = Regex.spaces.split(source); String sourceLeafName = sourceTokens[currentSourceIndex]; for (int i = currentSourceIndex + 1; i < leftMost.sourceStart(); i++) sourceLeafName += " " + sourceTokens[i]; addVertexWithContext(sourceLeafName, currSource, true); currentSourceIndex = leftMost.sourceStart(); } else { currentSourceIndex = addSourceNodes(leftMost, currSource, leftMost.sourceStart()); children.remove(leftMost); } } // HACK ALERT: // for some reason, the ROOT node in joshua output has a listed source span that is // one token longer than the actual source sentence. so we have to correct for that. int actualSourceEnd; if (parent == null) // ROOT node actualSourceEnd = currSource.sourceEnd() - 1; else actualSourceEnd = currSource.sourceEnd(); if (actualSourceEnd > Regex.spaces.split(source).length) actualSourceEnd = Regex.spaces.split(source).length; if (currentSourceIndex < actualSourceEnd) { String [] sourceTokens = Regex.spaces.split(source); String sourceLeafName = sourceTokens[currentSourceIndex]; for (int i = currentSourceIndex + 1; i < actualSourceEnd; i++) sourceLeafName += " " + sourceTokens[i]; addVertexWithContext(sourceLeafName,currSource, true); currentSourceIndex = actualSourceEnd; } return currentSourceIndex; } public void addCorrespondences() { for (Node v : vertices) { Node s = v.getCounterpart(); if (s != null) addEdge(new DerivationTreeEdge(true), v, s); } } public void setSubtreeHighlight(Node n, boolean b) { n.setHighlighted(b); for (Node s : getSuccessors(n)) { setSubtreeHighlight(s, b); } return; } }