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 FeatureFunction identifyFeature(String spec) throws MaltChainedException { 116 String[] items =splitPattern.split(spec); 117 Stack<Object> objects = new Stack<Object>(); 118 for (int i = items.length-1; i >= 0; i--) { 119 if (items[i].trim().length() != 0) { 120 objects.push(items[i].trim()); 121 } 122 } 123 identifyFeatureFunction(objects); 124 if (objects.size() != 1 || !(objects.peek() instanceof FeatureFunction) || (objects.peek() instanceof AddressFunction)) { 125 throw new FeatureException("The feature specification '"+spec+"' were not recognized properly. "); 126 } 127 return (FeatureFunction)objects.pop(); 128 } 129 130 protected void identifyFeatureFunction(Stack<Object> objects) throws MaltChainedException { 131 Function function = featureEngine.newFunction(objects.peek().toString(), registry); 132 if (function != null) { 133 objects.pop(); 134 if (!objects.isEmpty()) { 135 identifyFeatureFunction(objects); 136 } 137 initializeFunction(function, objects); 138 } else { 139 if (!objects.isEmpty()) { 140 Object o = objects.pop(); 141 if (!objects.isEmpty()) { 142 identifyFeatureFunction(objects); 143 } 144 objects.push(o); 145 } 146 } 147 } 148 149 protected void initializeFunction(Function function, Stack<Object> objects) throws MaltChainedException { 150 Class<?>[] paramTypes = function.getParameterTypes(); 151 Object[] arguments = new Object[paramTypes.length]; 152 for (int i = 0; i < paramTypes.length; i++) { 153 if (paramTypes[i] == java.lang.Integer.class) { 154 if (objects.peek() instanceof String) { 155 String object = (String)objects.pop(); 156 try { 157 objects.push(Integer.parseInt(object)); 158 } catch (NumberFormatException e) { 159 throw new FeatureException("The function '"+function.getClass()+"' cannot be initialized with argument '"+object+"'" + ", expect an integer value. ", e); 160 } 161 } else { 162 throw new FeatureException("The function '"+function.getClass()+"' cannot be initialized with argument '"+objects.peek()+"'" + ", expect an integer value. "); 163 } 164 } else if (paramTypes[i] == java.lang.Double.class) { 165 if (objects.peek() instanceof String) { 166 String object = (String)objects.pop(); 167 try { 168 objects.push(Double.parseDouble(object)); 169 } catch (NumberFormatException e) { 170 throw new FeatureException("The function '"+function.getClass()+"' cannot be initialized with argument '"+object+"'" + ", expect a numeric value. ", e); 171 } 172 } else { 173 throw new FeatureException("The function '"+function.getClass()+"' cannot be initialized with argument '"+objects.peek()+"'" + ", expect a numeric value. "); 174 } 175 } else if (paramTypes[i] == java.lang.Boolean.class) { 176 if (objects.peek() instanceof String) { 177 objects.push(Boolean.parseBoolean(((String)objects.pop()))); 178 } else { 179 throw new FeatureException("The function '"+function.getClass()+"' cannot be initialized with argument '"+objects.peek()+"'" + ", expect a boolean value. "); 180 181 } 182 } 183 if (!paramTypes[i].isInstance(objects.peek())) { 184 throw new FeatureException("The function '"+function.getClass()+"' cannot be initialized with argument '"+objects.peek()+"'"); 185 } 186 arguments[i] = objects.pop(); 187 } 188 function.initialize(arguments); 189 if (function instanceof AddressFunction) { 190 int index = getAddressFunctionCache().indexOf(function); 191 if (index != -1) { 192 function = getAddressFunctionCache().get(index); 193 } else { 194 getAddressFunctionCache().add((AddressFunction)function); 195 } 196 } else if (function instanceof FeatureFunction) { 197 int index = getFeatureFunctionCache().indexOf(function); 198 if (index != -1) { 199 function = getFeatureFunctionCache().get(index); 200 } else { 201 getFeatureFunctionCache().add((FeatureFunction)function); 202 } 203 } 204 objects.push(function); 205 } 206 207 public String toString() { 208 return specModel.toString(); 209 } 210 }