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 LDEPS, RDEPS, DEPS 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 normalizationString = (String)arguments[2]; 062 // Creates a symbol table called "NUMOF" using one null value 063 setSymbolTable(tableHandler.addSymbolTable("NUMOF"+normalizationString, ColumnDescription.INPUT, "one")); 064 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.setIndexCode(table.getNullValueCode(NullValueId.NO_NODE)); 142 featureValue.setSymbol(table.getNullValueSymbol(NullValueId.NO_NODE)); 143 featureValue.setNullValue(true); 144 } else { 145 // Unfortunately this method takes a lot of time arg1.getAddressClass().asSubclass(org.maltparser.core.syntaxgraph.node.DependencyNode.class); 146 // Cast the address arguments to dependency nodes 147 final DependencyNode node = (DependencyNode)arg1.getAddress(); 148 int numof = 0; 149 if (numOfRelation == NumOfRelation.DEPS) { 150 numof = node.getLeftDependentCount() + node.getRightDependentCount(); 151 } else if (numOfRelation == NumOfRelation.LDEPS) { 152 numof = node.getLeftDependentCount(); 153 } else if (numOfRelation == NumOfRelation.RDEPS) { 154 numof = node.getRightDependentCount(); 155 } 156 int lower = -1; 157 boolean f = false; 158 for (Integer upper : normalization.keySet()) { 159 if (numof >= lower && numof < upper) { 160 featureValue.setIndexCode(table.getSymbolStringToCode(normalization.get(lower))); 161 featureValue.setSymbol(normalization.get(lower)); 162 f = true; 163 break; 164 } 165 lower = upper; 166 } 167 if (f == false) { 168 featureValue.setIndexCode(table.getSymbolStringToCode(normalization.get(lower))); 169 featureValue.setSymbol(normalization.get(lower)); 170 } 171 // Tells the feature value that the feature is known and is not a null value 172 featureValue.setNullValue(false); 173 } 174 featureValue.setValue(1); 175 // featureValue.setKnown(true); 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 int getType() { 243 return ColumnDescription.STRING; 244 } 245 246 public String getMapIdentifier() { 247 return getSymbolTable().getName(); 248 } 249 250 public boolean equals(Object obj) { 251 if (this == obj) 252 return true; 253 if (obj == null) 254 return false; 255 if (getClass() != obj.getClass()) 256 return false; 257 return obj.toString().equals(this.toString()); 258 } 259 260 public int hashCode() { 261 return 217 + (null == toString() ? 0 : toString().hashCode()); 262 } 263 264 public String toString() { 265 final StringBuilder sb = new StringBuilder(); 266 sb.append("NumOf("); 267 sb.append(addressFunction.toString()); 268 sb.append(", "); 269 sb.append(numOfRelationName); 270 sb.append(", "); 271 sb.append(normalizationString); 272 sb.append(')'); 273 return sb.toString(); 274 } 275 }