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 }