001package org.maltparser.core.lw.graph;
002
003import java.util.HashSet;
004import java.util.Iterator;
005import java.util.Set;
006import java.util.SortedMap;
007import java.util.TreeMap;
008
009import org.maltparser.concurrent.graph.dataformat.ColumnDescription;
010import org.maltparser.core.exception.MaltChainedException;
011import org.maltparser.core.symbol.SymbolTable;
012import org.maltparser.core.symbol.SymbolTableHandler;
013import org.maltparser.core.syntaxgraph.LabelSet;
014import org.maltparser.core.syntaxgraph.LabeledStructure;
015import org.maltparser.core.syntaxgraph.edge.Edge;
016import org.maltparser.core.syntaxgraph.node.Node;
017
018/**
019* A lightweight version of org.maltparser.core.syntaxgraph.edge.GraphEdge.
020* 
021* @author Johan Hall
022*/
023public final class LWEdge implements Edge, Comparable<LWEdge> {
024        private final Node source;
025        private final Node target;
026        private final SortedMap<ColumnDescription, String> labels;
027        
028        protected LWEdge(LWEdge edge) throws LWGraphException {
029                this.source = edge.source;
030                this.target = edge.target;
031                this.labels = new TreeMap<ColumnDescription, String>(edge.labels);
032        }
033        
034        protected LWEdge(Node _source, Node _target, SortedMap<ColumnDescription, String> _labels) throws MaltChainedException {
035                if (_source.getBelongsToGraph() != _target.getBelongsToGraph()) {
036                throw new LWGraphException("The source node and target node must belong to the same dependency graph.");
037                }
038                this.source = _source;
039                this.target = _target;
040                this.labels = _labels;
041                SymbolTableHandler symbolTableHandler = getBelongsToGraph().getSymbolTables();
042                for (ColumnDescription column : labels.keySet()) {
043                        SymbolTable table = symbolTableHandler.addSymbolTable(column.getName());
044                        table.addSymbol(labels.get(column));
045                }
046        }
047        
048        protected LWEdge(Node _source, Node _target) throws MaltChainedException {
049                if (_source.getBelongsToGraph() != _target.getBelongsToGraph()) {
050                        throw new LWGraphException("The source node and target node must belong to the same dependency graph.");
051                }
052                this.source = _source;
053                this.target = _target;
054                this.labels = new TreeMap<ColumnDescription, String>();
055        }
056        
057        public Node getSource() {
058                return source;
059        }
060
061        public Node getTarget() {
062                return target;
063        }
064        
065        public String getLabel(ColumnDescription column) {
066                if (labels.containsKey(column)) {
067                        return labels.get(column);
068                } else if (column.getCategory() == ColumnDescription.IGNORE) {
069                        return column.getDefaultOutput();
070                }
071                return "";
072        }
073        
074        public int nLabels() {
075                return labels.size();
076        }
077        
078        public boolean isLabeled() {
079                return labels.size() > 0;
080        }
081
082        
083        @Override
084        public void setEdge(Node source, Node target, int type)
085                        throws MaltChainedException {
086                throw new LWGraphException("Not implemented in light-weight dependency graph");
087        }
088
089        @Override
090        public int getType() {
091                return DEPENDENCY_EDGE;
092        }
093
094        
095        /**
096         * Adds a label (a string value) to the symbol table and to the graph element. 
097         * 
098         * @param table the symbol table
099         * @param symbol a label symbol
100         * @throws MaltChainedException
101         */
102        public void addLabel(SymbolTable table, String symbol) throws MaltChainedException {
103                LWDependencyGraph graph = (LWDependencyGraph)getBelongsToGraph();
104                ColumnDescription column = graph.getDataFormat().getColumnDescription(table.getName());
105                table.addSymbol(symbol);
106                labels.put(column, symbol);
107        }
108        
109        /**
110         * Adds a label (an integer value) to the symbol table and to the graph element.
111         * 
112         * @param table the symbol table
113         * @param code a label code
114         * @throws MaltChainedException
115         */
116        public void addLabel(SymbolTable table, int code) throws MaltChainedException {
117                addLabel(table, table.getSymbolCodeToString(code));
118        }
119        
120        /**
121         * Adds the labels of the label set to the label set of the graph element.
122         * 
123         * @param labelSet a label set.
124         * @throws MaltChainedException
125         */
126        public void addLabel(LabelSet labelSet) throws MaltChainedException {
127                for (SymbolTable table : labelSet.keySet()) {
128                        addLabel(table, labelSet.get(table));
129                }
130        }
131        
132        /**
133         * Returns <i>true</i> if the graph element has a label for the symbol table, otherwise <i>false</i>.
134         * 
135         * @param table the symbol table
136         * @return <i>true</i> if the graph element has a label for the symbol table, otherwise <i>false</i>.
137         * @throws MaltChainedException
138         */
139        public boolean hasLabel(SymbolTable table) throws MaltChainedException {
140                if (table == null) {
141                        return false;
142                }
143                LWDependencyGraph graph = (LWDependencyGraph)getBelongsToGraph();
144                ColumnDescription column = graph.getDataFormat().getColumnDescription(table.getName());
145                return labels.containsKey(column);
146        }
147        
148        /**
149         * Returns the label symbol(a string representation) of the symbol table if it exists, otherwise 
150         * an exception is thrown.
151         * 
152         * @param table the symbol table
153         * @return the label (a string representation) of the symbol table if it exists.
154         * @throws MaltChainedException
155         */
156        public String getLabelSymbol(SymbolTable table) throws MaltChainedException {
157                LWDependencyGraph graph = (LWDependencyGraph)getBelongsToGraph();
158                ColumnDescription column = graph.getDataFormat().getColumnDescription(table.getName());
159                return labels.get(column);
160        }
161        
162        /**
163         * Returns the label code (an integer representation) of the symbol table if it exists, otherwise 
164         * an exception is thrown.
165         * 
166         * @param table the symbol table
167         * @return the label code (an integer representation) of the symbol table if it exists
168         * @throws MaltChainedException
169         */
170        public int getLabelCode(SymbolTable table) throws MaltChainedException {
171                LWDependencyGraph graph = (LWDependencyGraph)getBelongsToGraph();
172                ColumnDescription column = graph.getDataFormat().getColumnDescription(table.getName());
173                return table.getSymbolStringToCode(labels.get(column));
174        }
175        
176        /**
177         * Returns a set of symbol tables (labeling functions or label types) that labels the graph element.
178         * 
179         * @return a set of symbol tables (labeling functions or label types)
180         */
181        public Set<SymbolTable> getLabelTypes() {
182                Set<SymbolTable> labelTypes = new HashSet<SymbolTable>();
183                SymbolTableHandler symbolTableHandler = getBelongsToGraph().getSymbolTables();
184                for (ColumnDescription column : labels.keySet()) {
185                        try {
186                                labelTypes.add(symbolTableHandler.getSymbolTable(column.getName()));
187                        } catch (MaltChainedException e) {
188                                e.printStackTrace();
189                        }
190                }
191                return labelTypes;
192        }
193        
194        /**
195         * Returns the label set.
196         * 
197         * @return the label set.
198         */
199        public LabelSet getLabelSet() {
200                SymbolTableHandler symbolTableHandler = getBelongsToGraph().getSymbolTables();
201                LabelSet labelSet = new LabelSet();
202                
203                for (ColumnDescription column : labels.keySet()) {
204                        try {
205                                SymbolTable table = symbolTableHandler.getSymbolTable(column.getName());
206                                int code = table.getSymbolStringToCode(labels.get(column));
207                                labelSet.put(table, code);
208                        } catch (MaltChainedException e) {
209                                e.printStackTrace();
210                        }
211                }
212                return labelSet;
213        }
214        
215        public void removeLabel(SymbolTable table) throws MaltChainedException {
216                LWDependencyGraph graph = (LWDependencyGraph)getBelongsToGraph();
217                ColumnDescription column = graph.getDataFormat().getColumnDescription(table.getName());
218                labels.remove(column);
219        }
220        
221        public void removeLabels() throws MaltChainedException {
222                labels.clear();
223        }
224        
225        /**
226         * Returns the graph (structure) in which the graph element belongs to. 
227         * 
228         * @return the graph (structure) in which the graph element belongs to. 
229         */
230        public LabeledStructure getBelongsToGraph() {
231                return target.getBelongsToGraph();
232        }
233        
234        public void setBelongsToGraph(LabeledStructure belongsToGraph) { }
235        
236
237        /**
238         * Resets the graph element.
239         * 
240         * @throws MaltChainedException
241         */
242        public void clear() throws MaltChainedException {
243                labels.clear();
244        }
245        
246        public int compareTo(LWEdge that) {
247                final int BEFORE = -1;
248            final int EQUAL = 0;
249            final int AFTER = 1;
250            
251            if (this == that) return EQUAL;
252            
253            if (this.target.getIndex() < that.target.getIndex()) return BEFORE;
254            if (this.target.getIndex() > that.target.getIndex()) return AFTER;
255            
256            if (this.source.getIndex() < that.source.getIndex()) return BEFORE;
257            if (this.source.getIndex() > that.source.getIndex()) return AFTER;
258            
259            
260            if (this.labels.equals(that.labels)) return EQUAL;
261                
262                Iterator<ColumnDescription> itthis = this.labels.keySet().iterator();
263                Iterator<ColumnDescription> itthat = that.labels.keySet().iterator();
264                while (itthis.hasNext() && itthat.hasNext()) {
265                        ColumnDescription keythis = itthis.next();
266                        ColumnDescription keythat = itthat.next();
267                        if (keythis.getPosition() < keythat.getPosition()) return BEFORE;
268                        if (keythis.getPosition() > keythat.getPosition()) return AFTER;
269                        if (this.labels.get(keythis).compareTo(that.labels.get(keythat)) != EQUAL) {
270                                return this.labels.get(keythis).compareTo(that.labels.get(keythat));
271                        }       
272                }
273                if (itthis.hasNext() == false && itthat.hasNext() == true) return BEFORE;
274                if (itthis.hasNext() == true && itthat.hasNext() == false) return AFTER;
275
276            
277                return EQUAL;
278        }
279        
280        @Override
281        public int hashCode() {
282                final int prime = 31;
283                int result = 1;
284                result = prime * result + source.getIndex();
285                result = prime * result + target.getIndex();
286                result = prime * result + ((labels == null) ? 0 : labels.hashCode());
287                return result;
288        }
289
290        @Override
291        public boolean equals(Object obj) {
292                if (this == obj)
293                        return true;
294                if (obj == null)
295                        return false;
296                if (getClass() != obj.getClass())
297                        return false;
298                LWEdge other = (LWEdge) obj;
299                if (source.getIndex() != other.source.getIndex())
300                        return false;
301                if (target.getIndex() != other.target.getIndex())
302                        return false;
303                if (labels == null) {
304                        if (other.labels != null)
305                                return false;
306                } else if (!labels.equals(other.labels))
307                        return false;
308                return true;
309        }
310        
311        public String toString() {
312                final StringBuilder sb = new StringBuilder();
313                sb.append(source);
314                sb.append(" -> ");
315                sb.append(target);
316                if (labels.size() > 0) {
317                        int i = 1;
318                        sb.append(" {");
319                        for (ColumnDescription column : labels.keySet()) {
320                                sb.append(column.getName());
321                                sb.append('=');
322                                sb.append(labels.get(column));
323                                if (i < labels.size()) {
324                                        sb.append(',');
325                                }
326                                i++;
327                        }
328                        sb.append(" }");
329                }
330                return sb.toString();
331        }
332}