001 package org.maltparser.core.syntaxgraph.feature;
002
003 import java.util.LinkedHashMap;
004 import java.util.Map;
005
006 import org.maltparser.core.exception.MaltChainedException;
007 import org.maltparser.core.feature.function.AddressFunction;
008 import org.maltparser.core.feature.function.FeatureFunction;
009 import org.maltparser.core.feature.value.AddressValue;
010 import org.maltparser.core.feature.value.FeatureValue;
011 import org.maltparser.core.feature.value.SingleFeatureValue;
012 import org.maltparser.core.io.dataformat.ColumnDescription;
013 import org.maltparser.core.symbol.SymbolTable;
014 import org.maltparser.core.symbol.SymbolTableHandler;
015 import org.maltparser.core.symbol.nullvalue.NullValues.NullValueId;
016 import org.maltparser.core.syntaxgraph.SyntaxGraphException;
017 import org.maltparser.core.syntaxgraph.node.DependencyNode;
018
019 public class NumOfFeature implements FeatureFunction {
020 public enum NumOfRelation {
021 LDEP, RDEP, DEP
022 };
023 protected AddressFunction addressFunction;
024 protected SymbolTableHandler tableHandler;
025 protected SymbolTable table;
026 protected SingleFeatureValue featureValue;
027 protected NumOfRelation numOfRelation;
028 protected String numOfRelationName;
029 protected String normalizationString;
030 protected Map<Integer,String> normalization;
031
032 public NumOfFeature(SymbolTableHandler tableHandler) throws MaltChainedException {
033 super();
034 featureValue = new SingleFeatureValue(this);
035 setTableHandler(tableHandler);
036 normalization = new LinkedHashMap<Integer,String>();
037 }
038
039 /**
040 * Initialize the distance feature function
041 *
042 * @param arguments an array of arguments with the type returned by getParameterTypes()
043 * @throws MaltChainedException
044 */
045 public void initialize(Object[] arguments) throws MaltChainedException {
046 if (arguments.length != 3) {
047 throw new SyntaxGraphException("Could not initialize NumOfFeature: number of arguments are not correct. ");
048 }
049 // Checks that the two arguments are address functions
050 if (!(arguments[0] instanceof AddressFunction)) {
051 throw new SyntaxGraphException("Could not initialize NumOfFeature: the first argument is not an address function. ");
052 }
053 if (!(arguments[1] instanceof java.lang.String)) {
054 throw new SyntaxGraphException("Could not initialize NumOfFeature: the second argument (relation) is not a string. ");
055 }
056 if (!(arguments[2] instanceof java.lang.String)) {
057 throw new SyntaxGraphException("Could not initialize NumOfFeature: the third argument (normalization) is not a string. ");
058 }
059 setAddressFunction((AddressFunction)arguments[0]);
060 setNumOfRelation((String)arguments[1]);
061
062 // Creates a symbol table called "NUMOF" using one null value
063 setSymbolTable(tableHandler.addSymbolTable("NUMOF", ColumnDescription.INPUT, "one"));
064 normalizationString = (String)arguments[2];
065 String[] items = normalizationString.split("\\|");
066
067 if (items.length <= 0 || !items[0].equals("0")) {
068 throw new SyntaxGraphException("Could not initialize NumOfFeature ("+this+"): the third argument (normalization) must contain a list of integer values separated with | and the first element must be 0.");
069 }
070 int tmp = -1;
071 for (int i = 0; i < items.length; i++) {
072 int v;
073 try {
074 v = Integer.parseInt(items[i]);
075 } catch (NumberFormatException e) {
076 throw new SyntaxGraphException("Could not initialize NumOfFeature ("+this+"): the third argument (normalization) must contain a sorted list of integer values separated with |", e);
077 }
078 normalization.put(v, ">="+v);
079 table.addSymbol(">="+v);
080 if (tmp != -1 && tmp >= v) {
081 throw new SyntaxGraphException("Could not initialize NumOfFeature ("+this+"): the third argument (normalization) must contain a sorted list of integer values separated with |");
082 }
083 tmp = v;
084 }
085 }
086
087 /**
088 * Returns an array of class types used by the feature extraction system to invoke initialize with
089 * correct arguments.
090 *
091 * @return an array of class types
092 */
093 public Class<?>[] getParameterTypes() {
094 Class<?>[] paramTypes = { org.maltparser.core.feature.function.AddressFunction.class,
095 java.lang.String.class,
096 java.lang.String.class};
097 return paramTypes;
098 }
099
100 /**
101 * Returns the string representation of the integer <code>code</code> according to the numof feature function.
102 *
103 * @param code the integer representation of the symbol
104 * @return the string representation of the integer <code>code</code> according to the numof feature function.
105 * @throws MaltChainedException
106 */
107 public String getSymbol(int code) throws MaltChainedException {
108 return table.getSymbolCodeToString(code);
109 }
110
111 /**
112 * Returns the integer representation of the string <code>symbol</code> according to the numof feature function.
113 *
114 * @param symbol the string representation of the symbol
115 * @return the integer representation of the string <code>symbol</code> according to the numof feature function.
116 * @throws MaltChainedException
117 */
118 public int getCode(String symbol) throws MaltChainedException {
119 return table.getSymbolStringToCode(symbol);
120 }
121
122 /**
123 * Cause the numof feature function to update the cardinality of the feature value.
124 *
125 * @throws MaltChainedException
126 */
127 public void updateCardinality() {
128 featureValue.setCardinality(table.getValueCounter());
129 }
130
131 /**
132 * Cause the feature function to update the feature value.
133 *
134 * @throws MaltChainedException
135 */
136 public void update() throws MaltChainedException {
137 // Retrieve the address value
138 final AddressValue arg1 = addressFunction.getAddressValue();
139 // if arg1 or arg2 is null, then set a NO_NODE null value as feature value
140 if (arg1.getAddress() == null ) {
141 featureValue.setCode(table.getNullValueCode(NullValueId.NO_NODE));
142 featureValue.setSymbol(table.getNullValueSymbol(NullValueId.NO_NODE));
143 featureValue.setKnown(true);
144 featureValue.setNullValue(true);
145 } else {
146 // Unfortunately this method takes a lot of time arg1.getAddressClass().asSubclass(org.maltparser.core.syntaxgraph.node.DependencyNode.class);
147 // Cast the address arguments to dependency nodes
148 final DependencyNode node = (DependencyNode)arg1.getAddress();
149 int numof = 0;
150 if (numOfRelation == NumOfRelation.DEP) {
151 numof = node.getLeftDependentCount() + node.getRightDependentCount();
152 } else if (numOfRelation == NumOfRelation.LDEP) {
153 numof = node.getLeftDependentCount();
154 } else if (numOfRelation == NumOfRelation.RDEP) {
155 numof = node.getRightDependentCount();
156 }
157 int lower = -1;
158 boolean f = false;
159 for (Integer upper : normalization.keySet()) {
160 if (numof >= lower && numof < upper) {
161 featureValue.setCode(table.getSymbolStringToCode(normalization.get(lower)));
162 featureValue.setSymbol(normalization.get(lower));
163 f = true;
164 break;
165 }
166 lower = upper;
167 }
168 if (f == false) {
169 featureValue.setCode(table.getSymbolStringToCode(normalization.get(lower)));
170 featureValue.setSymbol(normalization.get(lower));
171 }
172 // Tells the feature value that the feature is known and is not a null value
173 featureValue.setKnown(true);
174 featureValue.setNullValue(false);
175 }
176 }
177
178 public void setNumOfRelation(String numOfRelationName) {
179 this.numOfRelationName = numOfRelationName;
180 numOfRelation = NumOfRelation.valueOf(numOfRelationName.toUpperCase());
181 }
182
183 public NumOfRelation getNumOfRelation() {
184 return numOfRelation;
185 }
186
187 /**
188 * Returns the feature value
189 *
190 * @return the feature value
191 */
192 public FeatureValue getFeatureValue() {
193 return featureValue;
194 }
195
196 /**
197 * Returns the symbol table used by the numof feature function
198 *
199 * @return the symbol table used by the numof feature function
200 */
201 public SymbolTable getSymbolTable() {
202 return table;
203 }
204
205 /**
206 * Returns the address function
207 *
208 * @return the address function
209 */
210 public AddressFunction getAddressFunction() {
211 return addressFunction;
212 }
213
214
215 /**
216 * Sets the address function
217 *
218 * @param addressFunction a address function
219 */
220 public void setAddressFunction(AddressFunction addressFunction) {
221 this.addressFunction = addressFunction;
222 }
223
224 /**
225 * Sets the symbol table handler
226 *
227 * @param tableHandler a symbol table handler
228 */
229 public void setTableHandler(SymbolTableHandler tableHandler) {
230 this.tableHandler = tableHandler;
231 }
232
233 /**
234 * Sets the symbol table used by the numof feature function
235 *
236 * @param table
237 */
238 public void setSymbolTable(SymbolTable table) {
239 this.table = table;
240 }
241
242 public boolean equals(Object obj) {
243 if (this == obj)
244 return true;
245 if (obj == null)
246 return false;
247 if (getClass() != obj.getClass())
248 return false;
249 return obj.toString().equals(this.toString());
250 }
251
252 public int hashCode() {
253 return 217 + (null == toString() ? 0 : toString().hashCode());
254 }
255
256 public String toString() {
257 final StringBuilder sb = new StringBuilder();
258 sb.append("NumOf(");
259 sb.append(addressFunction.toString());
260 sb.append(", ");
261 sb.append(numOfRelationName);
262 sb.append(", ");
263 sb.append(normalizationString);
264 sb.append(')');
265 return sb.toString();
266 }
267 }