001 package org.maltparser.parser.algorithm.nivre; 002 003 import java.util.Stack; 004 005 import org.maltparser.core.exception.MaltChainedException; 006 import org.maltparser.core.symbol.SymbolTable; 007 import org.maltparser.core.symbol.SymbolTableHandler; 008 import org.maltparser.core.syntaxgraph.DependencyGraph; 009 import org.maltparser.core.syntaxgraph.DependencyStructure; 010 import org.maltparser.core.syntaxgraph.edge.Edge; 011 import org.maltparser.core.syntaxgraph.node.DependencyNode; 012 import org.maltparser.parser.ParserConfiguration; 013 import org.maltparser.parser.ParsingException; 014 /** 015 * @author Johan Hall 016 * 017 */ 018 public class NivreConfig extends ParserConfiguration { 019 private final Stack<DependencyNode> stack; 020 private final Stack<DependencyNode> input; 021 private final DependencyStructure dependencyGraph; 022 023 private boolean allowRoot; 024 private boolean allowReduce; 025 026 public NivreConfig(SymbolTableHandler symbolTableHandler, boolean allowRoot, boolean allowReduce) throws MaltChainedException { 027 super(); 028 stack = new Stack<DependencyNode>(); 029 input = new Stack<DependencyNode>(); 030 dependencyGraph = new DependencyGraph(symbolTableHandler); 031 setAllowRoot(allowRoot); 032 setAllowReduce(allowReduce); 033 } 034 035 public Stack<DependencyNode> getStack() { 036 return stack; 037 } 038 039 public Stack<DependencyNode> getInput() { 040 return input; 041 } 042 043 public DependencyStructure getDependencyStructure() { 044 return dependencyGraph; 045 } 046 047 public boolean isTerminalState() { 048 return input.isEmpty(); 049 } 050 051 public DependencyNode getStackNode(int index) throws MaltChainedException { 052 if (index < 0) { 053 throw new ParsingException("Stack index must be non-negative in feature specification. "); 054 } 055 if (stack.size()-index > 0) { 056 return stack.get(stack.size()-1-index); 057 } 058 return null; 059 } 060 061 public DependencyNode getInputNode(int index) throws MaltChainedException { 062 if (index < 0) { 063 throw new ParsingException("Input index must be non-negative in feature specification. "); 064 } 065 if (input.size()-index > 0) { 066 return input.get(input.size()-1-index); 067 } 068 return null; 069 } 070 071 public void setDependencyGraph(DependencyStructure source) throws MaltChainedException { 072 dependencyGraph.clear(); 073 for (int index : source.getTokenIndices()) { 074 final DependencyNode gnode = source.getTokenNode(index); 075 final DependencyNode pnode = dependencyGraph.addTokenNode(gnode.getIndex()); 076 for (SymbolTable table : gnode.getLabelTypes()) { 077 pnode.addLabel(table, gnode.getLabelSymbol(table)); 078 } 079 080 if (gnode.hasHead()) { 081 final Edge s = gnode.getHeadEdge(); 082 final Edge t = dependencyGraph.addDependencyEdge(s.getSource().getIndex(), s.getTarget().getIndex()); 083 084 for (SymbolTable table : s.getLabelTypes()) { 085 t.addLabel(table, s.getLabelSymbol(table)); 086 } 087 } 088 } 089 for (SymbolTable table : source.getDefaultRootEdgeLabels().keySet()) { 090 dependencyGraph.setDefaultRootEdgeLabel(table, source.getDefaultRootEdgeLabelSymbol(table)); 091 } 092 } 093 094 public DependencyStructure getDependencyGraph() { 095 return dependencyGraph; 096 } 097 098 public void initialize(ParserConfiguration parserConfiguration) throws MaltChainedException { 099 if (parserConfiguration != null) { 100 final NivreConfig nivreConfig = (NivreConfig)parserConfiguration; 101 final Stack<DependencyNode> sourceStack = nivreConfig.getStack(); 102 final Stack<DependencyNode> sourceInput = nivreConfig.getInput(); 103 setDependencyGraph(nivreConfig.getDependencyGraph()); 104 for (int i = 0, n = sourceStack.size(); i < n; i++) { 105 stack.add(dependencyGraph.getDependencyNode(sourceStack.get(i).getIndex())); 106 } 107 for (int i = 0, n = sourceInput.size(); i < n; i++) { 108 input.add(dependencyGraph.getDependencyNode(sourceInput.get(i).getIndex())); 109 } 110 } else { 111 stack.push(dependencyGraph.getDependencyRoot()); 112 for (int i = dependencyGraph.getHighestTokenIndex(); i > 0; i--) { 113 final DependencyNode node = dependencyGraph.getDependencyNode(i); 114 if (node != null && !node.hasHead()) { // added !node.hasHead() 115 input.push(node); 116 } 117 } 118 } 119 } 120 121 public boolean isAllowRoot() { 122 return allowRoot; 123 } 124 125 public void setAllowRoot(boolean allowRoot) { 126 this.allowRoot = allowRoot; 127 } 128 129 public boolean isAllowReduce() { 130 return allowReduce; 131 } 132 133 public void setAllowReduce(boolean allowReduce) { 134 this.allowReduce = allowReduce; 135 } 136 137 public void clear() throws MaltChainedException { 138 dependencyGraph.clear(); 139 stack.clear(); 140 input.clear(); 141 historyNode = null; 142 } 143 144 public boolean equals(Object obj) { 145 if (this == obj) 146 return true; 147 if (obj == null) 148 return false; 149 if (getClass() != obj.getClass()) 150 return false; 151 NivreConfig that = (NivreConfig)obj; 152 153 if (stack.size() != that.getStack().size()) 154 return false; 155 if (input.size() != that.getInput().size()) 156 return false; 157 if (dependencyGraph.nEdges() != that.getDependencyGraph().nEdges()) 158 return false; 159 for (int i = 0; i < stack.size(); i++) { 160 if (stack.get(i).getIndex() != that.getStack().get(i).getIndex()) { 161 return false; 162 } 163 } 164 for (int i = 0; i < input.size(); i++) { 165 if (input.get(i).getIndex() != that.getInput().get(i).getIndex()) { 166 return false; 167 } 168 } 169 return dependencyGraph.getEdges().equals(that.getDependencyGraph().getEdges()); 170 } 171 172 public String toString() { 173 final StringBuilder sb = new StringBuilder(); 174 sb.append(stack.size()); 175 sb.append(", "); 176 sb.append(input.size()); 177 sb.append(", "); 178 sb.append(dependencyGraph.nEdges()); 179 return sb.toString(); 180 } 181 }