1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package de.fu_berlin.ties.classify.feature;
23
24 import org.apache.commons.lang.StringUtils;
25 import org.apache.commons.lang.builder.ToStringBuilder;
26 import org.dom4j.Element;
27 import org.dom4j.QName;
28
29 import de.fu_berlin.ties.ProcessingException;
30 import de.fu_berlin.ties.TiesConfiguration;
31 import de.fu_berlin.ties.io.ObjectElement;
32 import de.fu_berlin.ties.io.XMLStorable;
33 import de.fu_berlin.ties.util.Util;
34 import de.fu_berlin.ties.xml.dom.DOMUtils;
35
36 /***
37 * A feature transformer transforms a feature vector in a suitable way.
38 * Feature transformer can be used for feature selection (discarding irrelevant
39 * features), for combining features etc. Feature transformers can be
40 * <em>chained</em> -- in this case each feature transformer will work on the
41 * featured returned by the previous one.
42 *
43 * @author Christian Siefkes
44 * @version $Revision: 1.11 $, $Date: 2006/10/21 16:03:57 $, $Author: siefkes $
45 */
46 public abstract class FeatureTransformer implements XMLStorable {
47
48 /***
49 * Name of the main element used for XML serialization.
50 */
51 public static final QName ELEMENT_MAIN =
52 DOMUtils.defaultName("transformer");
53
54 /***
55 * Configuration key specifying the list of transformers to chain.
56 */
57 public static final String CONFIG_TRANSFORMERS = "transformer.chain";
58
59 /***
60 * Factory method that delegates to {@link #createTransformer()} using the
61 * {@linkplain TiesConfiguration#CONF standard configuration}.
62 *
63 * @return the last transformer in the created transformer chain; or
64 * <code>null</code> is no transformers are specified (parameter value is
65 * <code>null</code> or empty)
66 * @throws IllegalArgumentException if the value of the
67 * {@link #CONFIG_TRANSFORMERS} key is invalid
68 * @throws ProcessingException if an error occurred while creating the
69 * transformer
70 */
71 public static FeatureTransformer createTransformer()
72 throws IllegalArgumentException, ProcessingException {
73 return createTransformer(TiesConfiguration.CONF);
74 }
75
76 /***
77 * Factory method that creates a feature transformer based on the
78 * {@link #CONFIG_TRANSFORMERS} key in the provided configuration.
79 * This parameter must contain a list fully specified names of subclasses
80 * of this class) used in a chain.
81 *
82 * <p>Eeach specified transformer must provide a constructor accepting a
83 * preceding {@link FeatureTransformer} as first argument and a
84 * {@link TiesConfiguration} as second argument.
85 *
86 * @param config the configuration to use
87 * @return the last transformer in the created transformer chain; or
88 * <code>null</code> is no transformers are specified (parameter value is
89 * <code>null</code> or empty)
90 * @throws IllegalArgumentException if the value of the
91 * {@link #CONFIG_TRANSFORMERS} key is invalid
92 * @throws ProcessingException if an error occurred while creating the
93 * transformer
94 */
95 public static FeatureTransformer createTransformer(
96 final TiesConfiguration config)
97 throws IllegalArgumentException, ProcessingException {
98 final String[] paramValue = config.getStringArray(CONFIG_TRANSFORMERS);
99 FeatureTransformer transformer = null;
100 int i = 0;
101
102 try {
103 for (; i < paramValue.length; i++) {
104
105
106
107 if (StringUtils.isNotEmpty(paramValue[i])) {
108 transformer = (FeatureTransformer) Util.createObject(
109 Class.forName(paramValue[i]),
110 new Object[] {transformer, config},
111 new Class[] {FeatureTransformer.class,
112 TiesConfiguration.class});
113 }
114 }
115 } catch (ClassNotFoundException cnfe) {
116
117 throw new ProcessingException(
118 "Cannot create transformer chain from key "
119 + CONFIG_TRANSFORMERS + " because the class " + paramValue[i]
120 + " is missing: " + cnfe.toString());
121 } catch (InstantiationException ie) {
122
123 throw new ProcessingException(
124 "Cannot create transformer chain from key "
125 + CONFIG_TRANSFORMERS + " because instantation of the class "
126 + paramValue[i] + " failed: ", ie);
127 }
128
129
130 return transformer;
131 }
132
133 /***
134 * The preceding transformer used if this transformer is part of a
135 * <em>chain</em>; <code>null</code> otherwise.
136 */
137 private final FeatureTransformer precedingTransformer;
138
139 /***
140 * Creates a new instance.
141 *
142 * @param precTrans the preceding transformer to use if this transformer
143 * is part of a <em>chain</em>; <code>null</code> otherwise
144 */
145 public FeatureTransformer(final FeatureTransformer precTrans) {
146 super();
147 precedingTransformer = precTrans;
148 }
149
150 /***
151 * Creates a new instance from an XML element, fulfilling the
152 * recommandation of the {@link XMLStorable} interface.
153 *
154 * @param element the XML element containing the serialized representation
155 * @throws InstantiationException if the given element does not contain
156 * a valid transformer description
157 */
158 public FeatureTransformer(final Element element)
159 throws InstantiationException {
160
161 this((FeatureTransformer) ObjectElement.createNextObject(
162 element.elementIterator(ELEMENT_MAIN)));
163 }
164
165 /***
166 * Transforms a feature vector.
167 *
168 * @param orgFeatures the original feature vector to transform
169 * @return a new feature vector containing the transformed features
170 */
171 protected abstract FeatureVector doTransform(
172 final FeatureVector orgFeatures);
173
174 /***
175 * Returns the preceding transformer used if this transformer is part of a
176 * <em>chain</em>.
177 *
178 * @return the preceding transformer, if any; or <code>null</code> if this
179 * transformer is not part of a chain resp. is the first transformer in a
180 * chain
181 */
182 public FeatureTransformer getPrecedingTransformer() {
183 return precedingTransformer;
184 }
185
186 /***
187 * {@inheritDoc}
188 */
189 public ObjectElement toElement() {
190
191 final ObjectElement result =
192 new ObjectElement(ELEMENT_MAIN, this.getClass());
193
194
195 if (precedingTransformer != null) {
196 result.add(precedingTransformer.toElement());
197 }
198
199 return result;
200 }
201
202 /***
203 * Returns a string representation of this object.
204 *
205 * @return a textual representation
206 */
207 public String toString() {
208 final ToStringBuilder builder = new ToStringBuilder(this);
209
210 if (precedingTransformer != null) {
211 builder.append("preceding transformer", precedingTransformer);
212 }
213 return builder.toString();
214 }
215
216 /***
217 * Transforms a feature vector. This method calls itself on the
218 * {@linkplain #getPrecedingTransformer() preceding transformer} (if any)
219 * prior to delegating to the abstract {@link #doTransform(FeatureVector)}
220 * method.
221 *
222 * @param orgFeatures the original feature vector to transform
223 * @return a new feature vector containing the transformed features
224 */
225 public FeatureVector transform(final FeatureVector orgFeatures) {
226 final FeatureVector result;
227
228 if (precedingTransformer != null) {
229
230 result = doTransform(precedingTransformer.transform(orgFeatures));
231 } else {
232
233 result = doTransform(orgFeatures);
234 }
235
236
237 orgFeatures.setTransformed(result);
238 return result;
239 }
240
241 }