001 package org.maltparser.core.syntaxgraph;
002
003 import java.util.Iterator;
004 import java.util.SortedMap;
005 import java.util.SortedSet;
006 import java.util.TreeSet;
007
008 import org.maltparser.core.exception.MaltChainedException;
009 import org.maltparser.core.pool.ObjectPoolList;
010 import org.maltparser.core.symbol.SymbolTable;
011 import org.maltparser.core.symbol.SymbolTableHandler;
012 import org.maltparser.core.syntaxgraph.edge.Edge;
013 import org.maltparser.core.syntaxgraph.edge.GraphEdge;
014 import org.maltparser.core.syntaxgraph.node.ComparableNode;
015 import org.maltparser.core.syntaxgraph.node.DependencyNode;
016 import org.maltparser.core.syntaxgraph.node.Node;
017 import org.maltparser.core.syntaxgraph.node.Root;
018 /**
019 *
020 *
021 * @author Johan Hall
022 */
023 public class DependencyGraph extends Sentence implements DependencyStructure {
024 private final ObjectPoolList<Edge> edgePool;
025 private final SortedSet<Edge> graphEdges;
026 private Root root;
027 private boolean singleHeadedConstraint;
028 private RootLabels rootLabels;
029
030 public DependencyGraph(SymbolTableHandler symbolTables) throws MaltChainedException {
031 super(symbolTables);
032 setSingleHeadedConstraint(true);
033 root = new Root();
034 root.setBelongsToGraph(this);
035 graphEdges = new TreeSet<Edge>();
036 edgePool = new ObjectPoolList<Edge>() {
037 protected Edge create() { return new GraphEdge(); }
038 public void resetObject(Edge o) throws MaltChainedException { o.clear(); }
039 };
040 clear();
041 }
042
043 public DependencyNode addDependencyNode() throws MaltChainedException {
044 return addTokenNode();
045 }
046
047 public DependencyNode addDependencyNode(int index) throws MaltChainedException {
048 if (index == 0) {
049 return root;
050 }
051 return addTokenNode(index);
052 }
053
054 public DependencyNode getDependencyNode(int index) throws MaltChainedException {
055 if (index == 0) {
056 return root;
057 }
058 return getTokenNode(index);
059 }
060
061 public int nDependencyNode() {
062 return nTokenNode() + 1;
063 }
064
065 public int getHighestDependencyNodeIndex() {
066 if (hasTokens()) {
067 return getHighestTokenIndex();
068 }
069 return 0;
070 }
071
072 public Edge addDependencyEdge(int headIndex, int dependentIndex) throws MaltChainedException {
073 DependencyNode head = null;
074 DependencyNode dependent = null;
075 if (headIndex == 0) {
076 head = root;
077 } else if (headIndex > 0) {
078 head = getOrAddTerminalNode(headIndex);
079 }
080
081 if (dependentIndex > 0) {
082 dependent = getOrAddTerminalNode(dependentIndex);
083 }
084 return addDependencyEdge(head, dependent);
085 }
086
087 protected Edge addDependencyEdge(DependencyNode head, DependencyNode dependent) throws MaltChainedException {
088 if (head == null || dependent == null) {
089 throw new SyntaxGraphException("Head or dependent node is missing.");
090 } else if (!dependent.isRoot()) {
091 if (singleHeadedConstraint && dependent.hasHead()) {
092 return moveDependencyEdge(head, dependent);
093 }
094 DependencyNode hc = ((DependencyNode)head).findComponent();
095 DependencyNode dc = ((DependencyNode)dependent).findComponent();
096 if (hc != dc) {
097 link(hc, dc);
098 numberOfComponents--;
099 }
100 Edge e = edgePool.checkOut();
101 e.setBelongsToGraph(this);
102 e.setEdge((Node)head, (Node)dependent, Edge.DEPENDENCY_EDGE);
103 graphEdges.add(e);
104 return e;
105 } else {
106 throw new SyntaxGraphException("Head node is not a root node or a terminal node.");
107 }
108 }
109
110 public Edge moveDependencyEdge(int newHeadIndex, int dependentIndex) throws MaltChainedException {
111 DependencyNode newHead = null;
112 DependencyNode dependent = null;
113 if (newHeadIndex == 0) {
114 newHead = root;
115 } else if (newHeadIndex > 0) {
116 newHead = terminalNodes.get(newHeadIndex);
117 }
118
119 if (dependentIndex > 0) {
120 dependent = terminalNodes.get(dependentIndex);
121 }
122 return moveDependencyEdge(newHead, dependent);
123 }
124
125 protected Edge moveDependencyEdge(DependencyNode newHead, DependencyNode dependent) throws MaltChainedException {
126 if (dependent == null || !dependent.hasHead()) {
127 return null;
128 }
129 Edge headEdge = dependent.getHeadEdge();
130 LabelSet labels = checkOutNewLabelSet();
131 for (SymbolTable table : headEdge.getLabelTypes()) {
132 labels.put(table, headEdge.getLabelCode(table));
133 }
134 headEdge.clear();
135 headEdge.setBelongsToGraph(this);
136 headEdge.setEdge((Node)newHead, (Node)dependent, Edge.DEPENDENCY_EDGE);
137 headEdge.addLabel(labels);
138 labels.clear();
139 checkInLabelSet(labels);
140 return headEdge;
141 }
142
143 public void removeDependencyEdge(int headIndex, int dependentIndex) throws MaltChainedException {
144 Node head = null;
145 Node dependent = null;
146 if (headIndex == 0) {
147 head = root;
148 } else if (headIndex > 0) {
149 head = terminalNodes.get(headIndex);
150 }
151
152 if (dependentIndex > 0) {
153 dependent = terminalNodes.get(dependentIndex);
154 }
155 removeDependencyEdge(head, dependent);
156 }
157
158 protected void removeDependencyEdge(Node head, Node dependent) throws MaltChainedException {
159 if (head == null || dependent == null) {
160 throw new SyntaxGraphException("Head or dependent node is missing.");
161 } else if (!dependent.isRoot()) {
162 Iterator<Edge> ie = dependent.getIncomingEdgeIterator();
163
164 while (ie.hasNext()) {
165 Edge e = ie.next();
166 if (e.getSource() == head) {
167 graphEdges.remove(e);
168 ie.remove();
169 edgePool.checkIn(e);
170 }
171 }
172 } else {
173 throw new SyntaxGraphException("Head node is not a root node or a terminal node.");
174 }
175 }
176
177 public Edge addSecondaryEdge(ComparableNode source, ComparableNode target) throws MaltChainedException {
178 if (source == null || target == null) {
179 throw new SyntaxGraphException("Head or dependent node is missing.");
180 } else if (!target.isRoot()) {
181 Edge e = edgePool.checkOut();
182 e.setBelongsToGraph(this);
183 e.setEdge((Node)source, (Node)target, Edge.SECONDARY_EDGE);
184 graphEdges.add(e);
185 return e;
186 }
187 return null;
188 }
189
190 public void removeSecondaryEdge(ComparableNode source, ComparableNode target) throws MaltChainedException {
191 if (source == null || target == null) {
192 throw new SyntaxGraphException("Head or dependent node is missing.");
193 } else if (!target.isRoot()) {
194 Iterator<Edge> ie = ((Node)target).getIncomingEdgeIterator();
195 while (ie.hasNext()) {
196 Edge e = ie.next();
197 if (e.getSource() == source) {
198 ie.remove();
199 graphEdges.remove(e);
200 edgePool.checkIn(e);
201 }
202 }
203 }
204 }
205
206 // public boolean hasLabeledDependency(int index, SymbolTable table) {
207 // return (!getDependencyNode(index).isRoot() && getDependencyNode(index).getLabelCode(table) != null);
208 // }
209
210 public boolean hasLabeledDependency(int index) throws MaltChainedException {
211 return (getDependencyNode(index).hasHead() && getDependencyNode(index).getHeadEdge().isLabeled());
212 }
213
214 public boolean isConnected() {
215 return (numberOfComponents == 1);
216 }
217
218 public boolean isProjective() throws MaltChainedException {
219 for (int i : terminalNodes.keySet()) {
220 if (!terminalNodes.get(i).isProjective()) {
221 return false;
222 }
223 }
224 return true;
225 }
226
227 public boolean isTree() {
228 return isConnected() && isSingleHeaded();
229 }
230
231 public boolean isSingleHeaded() {
232 for (int i : terminalNodes.keySet()) {
233 if (!terminalNodes.get(i).hasAtMostOneHead()) {
234 return false;
235 }
236 }
237 return true;
238 }
239
240 public boolean isSingleHeadedConstraint() {
241 return singleHeadedConstraint;
242 }
243
244 public void setSingleHeadedConstraint(boolean singleHeadedConstraint) {
245 this.singleHeadedConstraint = singleHeadedConstraint;
246 }
247
248 public int nNonProjectiveEdges() throws MaltChainedException {
249 int c = 0;
250 for (int i : terminalNodes.keySet()) {
251 if (!terminalNodes.get(i).isProjective()) {
252 c++;
253 }
254 }
255 return c;
256 }
257
258 public int nEdges() {
259 return graphEdges.size();
260 }
261
262 public SortedSet<Edge> getEdges() {
263 return graphEdges;
264 }
265
266 public SortedSet<Integer> getDependencyIndices() {
267 SortedSet<Integer> indices = new TreeSet<Integer>(terminalNodes.keySet());
268 indices.add(0);
269 return indices;
270 }
271
272 protected DependencyNode link(DependencyNode x, DependencyNode y) {
273 if (x.getRank() > y.getRank()) {
274 y.setComponent(x);
275 } else {
276 x.setComponent(y);
277 if (x.getRank() == y.getRank()) {
278 y.setRank(y.getRank()+1);
279 }
280 return y;
281 }
282 return x;
283 }
284
285 public void linkAllTreesToRoot() throws MaltChainedException {
286 for (int i : terminalNodes.keySet()) {
287 if (!terminalNodes.get(i).hasHead()) {
288 addDependencyEdge(root,terminalNodes.get(i));
289 }
290 }
291 }
292
293 public LabelSet getDefaultRootEdgeLabels() throws MaltChainedException {
294 if (rootLabels == null) {
295 return null;
296 }
297 return rootLabels.getDefaultRootLabels();
298 }
299
300 public String getDefaultRootEdgeLabelSymbol(SymbolTable table) throws MaltChainedException {
301 if (rootLabels == null) {
302 return null;
303 }
304 return rootLabels.getDefaultRootLabelSymbol(table);
305 }
306
307 public int getDefaultRootEdgeLabelCode(SymbolTable table) throws MaltChainedException {
308 if (rootLabels == null) {
309 return -1;
310 }
311 return rootLabels.getDefaultRootLabelCode(table);
312 }
313
314 public void setDefaultRootEdgeLabel(SymbolTable table, String defaultRootSymbol) throws MaltChainedException {
315 if (rootLabels == null) {
316 rootLabels = new RootLabels();
317 }
318 rootLabels.setDefaultRootLabel(table, defaultRootSymbol);
319 }
320
321 public void setDefaultRootEdgeLabels(String rootLabelOption, SortedMap<String, SymbolTable> edgeSymbolTables) throws MaltChainedException {
322 if (rootLabels == null) {
323 rootLabels = new RootLabels();
324 }
325 rootLabels.setRootLabels(rootLabelOption, edgeSymbolTables);
326 }
327
328 public void clear() throws MaltChainedException {
329 edgePool.checkInAll();
330 graphEdges.clear();
331 root.clear();
332 super.clear();
333 numberOfComponents++;
334 }
335
336 public DependencyNode getDependencyRoot() {
337 return root;
338 }
339
340 public String toString() {
341 final StringBuilder sb = new StringBuilder();
342 for (int index : terminalNodes.keySet()) {
343 sb.append(terminalNodes.get(index).toString().trim());
344 sb.append('\n');
345 }
346 sb.append('\n');
347 return sb.toString();
348 }
349 }