001    package org.maltparser.core.feature;
002    
003    
004    import java.util.ArrayList;
005    import java.util.Stack;
006    import java.util.regex.Pattern;
007    
008    import org.maltparser.core.config.ConfigurationRegistry;
009    import org.maltparser.core.exception.MaltChainedException;
010    import org.maltparser.core.feature.function.AddressFunction;
011    import org.maltparser.core.feature.function.FeatureFunction;
012    import org.maltparser.core.feature.function.Function;
013    import org.maltparser.core.feature.spec.SpecificationModel;
014    import org.maltparser.core.feature.spec.SpecificationSubModel;
015    import org.maltparser.core.feature.system.FeatureEngine;
016    import org.maltparser.core.helper.HashMap;
017    
018    /**
019    *
020    *
021    * @author Johan Hall
022    */
023    public class FeatureModel extends HashMap<String, FeatureVector> {
024            public final static long serialVersionUID = 3256444702936019250L;
025            protected SpecificationModel specModel;
026            protected final ArrayList<AddressFunction> addressFunctionCache;
027            protected final ArrayList<FeatureFunction> featureFunctionCache;
028            protected ConfigurationRegistry registry;
029            protected FeatureEngine featureEngine;
030            protected FeatureVector mainFeatureVector = null; 
031            protected final Pattern splitPattern;
032            
033            public FeatureModel(SpecificationModel specModel, ConfigurationRegistry registry, FeatureEngine engine) throws MaltChainedException {
034                    setSpecModel(specModel);
035                    setRegistry(registry);
036                    setFeatureEngine(engine);
037                    addressFunctionCache = new ArrayList<AddressFunction>();
038                    featureFunctionCache = new ArrayList<FeatureFunction>();
039                    splitPattern = Pattern.compile("\\(|\\)|\\[|\\]|,");
040                    for (SpecificationSubModel subModel : specModel) {
041                            FeatureVector fv = new FeatureVector(this, subModel);
042                            if (mainFeatureVector == null) {
043                                    if (subModel.getSubModelName().equals("MAIN")) {
044                                            mainFeatureVector = fv;
045                                    } else {
046                                            mainFeatureVector = fv;
047                                            put(subModel.getSubModelName(), fv);
048                                    }
049                            } else {
050                                    put(subModel.getSubModelName(), fv);
051                            }
052                    }
053            }
054    
055            public SpecificationModel getSpecModel() {
056                    return specModel;
057            }
058    
059            public void setSpecModel(SpecificationModel specModel) {
060                    this.specModel = specModel;
061            }
062            
063            public ArrayList<AddressFunction> getAddressFunctionCache() {
064                    return addressFunctionCache;
065            }
066    
067            public ArrayList<FeatureFunction> getFeatureFunctionCache() {
068                    return featureFunctionCache;
069            }
070            
071            public ConfigurationRegistry getRegistry() {
072                    return registry;
073            }
074    
075            public void setRegistry(ConfigurationRegistry registry) {
076                    this.registry = registry;
077            }
078    
079            public FeatureEngine getFeatureEngine() {
080                    return featureEngine;
081            }
082    
083            public void setFeatureEngine(FeatureEngine featureEngine) {
084                    this.featureEngine = featureEngine;
085            }
086            
087            public FeatureVector getMainFeatureVector() {
088                    return mainFeatureVector;
089            }
090            
091            public FeatureVector getFeatureVector(String subModelName) {
092                    return get(subModelName);
093            }
094            
095            public void update() throws MaltChainedException {
096                    for (int i = 0, n = addressFunctionCache.size(); i < n; i++) {
097                            addressFunctionCache.get(i).update();
098                    }
099                    
100                    for (int i = 0, n = featureFunctionCache.size(); i < n; i++) {
101                            featureFunctionCache.get(i).update();
102                    }
103            }
104            
105            public void update(Object[] arguments) throws MaltChainedException {
106                    for (int i = 0, n = addressFunctionCache.size(); i < n; i++) {
107                            addressFunctionCache.get(i).update(arguments);
108                    }
109                    
110                    for (int i = 0, n = featureFunctionCache.size(); i < n; i++) {
111                            featureFunctionCache.get(i).update();
112                    }
113            }
114            
115    //      public void updateCardinality() throws MaltChainedException {
116    //              for (int i = 0, n = featureFunctionCache.size(); i < n; i++) {
117    //                      featureFunctionCache.get(i).updateCardinality();
118    //              }
119    //      }
120            
121            public FeatureFunction identifyFeature(String spec) throws MaltChainedException {
122                    String[] items =splitPattern.split(spec);
123                    Stack<Object> objects = new Stack<Object>();
124                    for (int i = items.length-1; i >= 0; i--) {
125                            if (items[i].trim().length() != 0) {
126                                    objects.push(items[i].trim());
127                            }
128                    }
129                    identifyFeatureFunction(objects);
130                    if (objects.size() != 1 || !(objects.peek() instanceof FeatureFunction) || (objects.peek() instanceof AddressFunction)) {
131                            throw new FeatureException("The feature specification '"+spec+"' were not recognized properly. ");
132                    }
133                    return (FeatureFunction)objects.pop();
134            }
135            
136            protected void identifyFeatureFunction(Stack<Object> objects) throws MaltChainedException {
137                    Function function = featureEngine.newFunction(objects.peek().toString(), registry);
138                    if (function != null) {
139                            objects.pop();
140                            if (!objects.isEmpty()) {
141                                    identifyFeatureFunction(objects);
142                            }
143                            initializeFunction(function, objects);
144                    } else {
145                            if (!objects.isEmpty()) {
146                                    Object o = objects.pop();
147                                    if (!objects.isEmpty()) {
148                                            identifyFeatureFunction(objects);
149                                    }
150                                    objects.push(o);
151                            }
152                    }
153            }
154            
155            protected void initializeFunction(Function function, Stack<Object> objects) throws MaltChainedException {
156                    Class<?>[] paramTypes = function.getParameterTypes();
157                    Object[] arguments = new Object[paramTypes.length];
158                    for (int i = 0; i < paramTypes.length; i++) {
159                            if (paramTypes[i] == java.lang.Integer.class) {
160                                    if (objects.peek() instanceof String) {
161                                            String object = (String)objects.pop();
162                                            try {
163                                                    objects.push(Integer.parseInt(object));
164                                            } catch (NumberFormatException e) {
165                                                    throw new FeatureException("The function '"+function.getClass()+"' cannot be initialized with argument '"+object+"'" + ", expect an integer value. ", e);
166                                            }
167                                    } else {
168                                            throw new FeatureException("The function '"+function.getClass()+"' cannot be initialized with argument '"+objects.peek()+"'" + ", expect an integer value. ");
169                                    }
170                            } else if (paramTypes[i] == java.lang.Double.class) {
171                                    if (objects.peek() instanceof String) {
172                                            String object = (String)objects.pop();
173                                            try {
174                                                    objects.push(Double.parseDouble(object));
175                                            } catch (NumberFormatException e) {
176                                                    throw new FeatureException("The function '"+function.getClass()+"' cannot be initialized with argument '"+object+"'" + ", expect a numeric value. ", e);
177                                            }
178                                    } else {
179                                            throw new FeatureException("The function '"+function.getClass()+"' cannot be initialized with argument '"+objects.peek()+"'" + ", expect a numeric value. ");
180                                    }
181                            } else if (paramTypes[i] == java.lang.Boolean.class) {
182                                    if (objects.peek() instanceof String) {
183                                            objects.push(Boolean.parseBoolean(((String)objects.pop())));
184                                    } else {
185                                            throw new FeatureException("The function '"+function.getClass()+"' cannot be initialized with argument '"+objects.peek()+"'" + ", expect a boolean value. ");
186                                            
187                                    }
188                            }
189                            if (!paramTypes[i].isInstance(objects.peek())) {
190                                    throw new FeatureException("The function '"+function.getClass()+"' cannot be initialized with argument '"+objects.peek()+"'");
191                            }
192                            arguments[i] = objects.pop();
193                    }
194                    function.initialize(arguments);
195                    if (function instanceof AddressFunction) {
196                            int index = getAddressFunctionCache().indexOf(function);
197                            if (index != -1) {
198                                    function = getAddressFunctionCache().get(index);
199                            } else {
200                                    getAddressFunctionCache().add((AddressFunction)function);
201                            }
202                    } else if (function instanceof FeatureFunction) {
203                            int index = getFeatureFunctionCache().indexOf(function);
204                            if (index != -1) {
205                                    function = getFeatureFunctionCache().get(index);
206                            } else {
207                                    getFeatureFunctionCache().add((FeatureFunction)function);
208                            }
209                    }
210                    objects.push(function);
211            }
212            
213            public String toString() {
214                    return specModel.toString();
215            }
216    }