    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