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 }