    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    }