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