1   /*
2    *  Copyright (c) 1998-2005, The University of Sheffield.
3    *
4    *  This file is part of GATE (see http://gate.ac.uk/), and is free
5    *  software, licenced under the GNU Library General Public License,
6    *  Version 2, June 1991 (in the distribution as file licence.html,
7    *  and also available at http://gate.ac.uk/gate/licence.html).
8    *
9    *  Valentin Tablan 19/11/2002
10   *  semantic type added by Mike Dowman 31-03-2004
11   *  Weightings added by Mike Dowman 24-5-2004
12   *
13   *  $Id: Attribute.java,v 1.9 2005/10/18 11:52:16 nirajaswani Exp $
14   *
15   */
16  package gate.creole.ml;
17  
18  import java.io.Serializable;
19  import java.util.ArrayList;
20  import java.util.Iterator;
21  
22  import org.jdom.Element;
23  
24  import gate.util.GateException;
25  
26  /**
27   * Describes an attribute associated to a ML instance.
28   */
29  
30  public class Attribute implements Serializable{
31  
32    public Attribute(Element jdomElement) throws GateException {
33      //find the name
34      Element anElement = jdomElement.getChild("NAME");
35      if(anElement == null) throw new GateException(
36        "Required element \"NAME\" not present in attribute:\n" +
37        jdomElement.toString() + "!");
38      else name = anElement.getTextTrim();
39  
40      //find the type
41      anElement = jdomElement.getChild("TYPE");
42      if(anElement == null) throw new GateException(
43        "Required element \"TYPE\" not present in attribute:\n" +
44        jdomElement.toString() + "!");
45      else type = anElement.getTextTrim();
46  
47      //find the feature if present
48      anElement = jdomElement.getChild("FEATURE");
49      if(anElement != null)feature = anElement.getTextTrim();
50  
51      //find the position if present
52      anElement = jdomElement.getChild("POSITION");
53      if(anElement == null) position = 0;
54      else position = Integer.parseInt(anElement.getTextTrim());
55  
56      // find the weighting if present
57      anElement = jdomElement.getChild("WEIGHTING");
58      if (anElement == null) weighting = 1.0;
59      else weighting = Double.parseDouble(anElement.getTextTrim());
60  
61      //find the class if present
62      isClass = jdomElement.getChild("CLASS") != null;
63  
64      //find the allowed values if present
65      anElement = jdomElement.getChild("VALUES");
66      if(anElement == null) values = null;
67      else{
68        values = new ArrayList();
69        Iterator valuesIter = anElement.getChildren("VALUE").iterator();
70        while(valuesIter.hasNext()){
71          values.add(((Element)valuesIter.next()).getTextTrim());
72        }
73      }
74    }
75  
76    public Attribute(){
77      name = null;
78      type =null;
79      feature = null;
80      isClass = false;
81      position = 0;
82      values = null;
83      weighting = 1.0;
84    }
85  
86    public String toString(){
87      StringBuffer res = new StringBuffer();
88      res.append("Name: " + name + "\n");
89      res.append("Type: " + type + "\n");
90      res.append("Feature: " + feature + "\n");
91      res.append("Weighting: "+ weighting + "\n");
92      Iterator valIter = values.iterator();
93      while(valIter.hasNext()){
94        res.append("  Value:" + valIter.next().toString() + "\n");
95      }
96      return res.toString();
97    }
98  
99    /**  
100    * This method is a clone of gate.creole.mi.Attribute.parseSerie method with minor 
101    * changes to make it compatible with ML API. It basically given an attribute element
102    * first locates all required variable and creates multiple attributes for the given RANGE.
103    */
104   public static java.util.List parseSeries(Element jdomElement) throws GateException {
105       //find the name
106       Element anElement = jdomElement.getChild("NAME");
107       if(anElement == null) throw new GateException(
108         "Required element \"NAME\" not present in attribute:\n" +
109         jdomElement.toString() + "!");
110       
111       String name = anElement.getTextTrim();
112 
113     //find the type
114       anElement = jdomElement.getChild("TYPE");
115       if(anElement == null) throw new GateException(
116         "Required element \"TYPE\" not present in attribute:\n" +
117         jdomElement.toString() + "!");
118       
119       String type = anElement.getTextTrim();
120 
121     String feature = null;
122       
123       //find the feature if present
124       anElement = jdomElement.getChild("FEATURE");
125       if(anElement != null)feature = anElement.getTextTrim();
126 
127       int minpos = 0;
128       int maxpos = 0;
129       
130       //find the range of this element (e.g. from - to)
131       anElement = jdomElement.getChild("RANGE");
132       try {
133       minpos = Integer.parseInt(anElement.getAttributeValue("from").trim());
134       maxpos = Integer.parseInt(anElement.getAttributeValue("to").trim());
135       } catch (Exception e){
136         throw new GateException(
137                 "Range element is uncorrect:\n" +
138                 jdomElement.toString() + "!");
139       }
140       
141       double weighting = 1.0;
142       
143       // find the weighting if present
144       anElement = jdomElement.getChild("WEIGHTING");
145       if (anElement != null) weighting = Double.parseDouble(anElement.getTextTrim());
146 
147       //find the class if present
148       boolean isClass = jdomElement.getChild("CLASS") != null;
149       if (isClass){
150         throw new GateException(
151                 "Cannot define the class in a serie:\n" +
152                 jdomElement.toString() + "!");
153       }
154 
155   
156     java.util.List values = null;
157       //find the allowed values if present
158     anElement = jdomElement.getChild("VALUES");
159     if(anElement == null) values = null;
160     else{
161       values = new ArrayList();
162       Iterator valuesIter = anElement.getChildren("VALUE").iterator();
163       while(valuesIter.hasNext()){
164         values.add(((Element)valuesIter.next()).getTextTrim());
165       }
166     }
167     
168       // Create a list of Attributes
169       ArrayList attributes = new ArrayList();  
170       for (int position =minpos; position<maxpos+1;position++ ){
171         Attribute attribute = new Attribute();
172         attribute.setClass(false);
173         attribute.setFeature(feature);
174         attribute.setName(name+"_"+position);
175         attribute.setPosition(position);
176         attribute.setType(type);
177         attribute.setWeighting(weighting);
178     attribute.setValues(values);
179         attributes.add(attribute);
180       }
181       return attributes;
182   }
183   
184   
185   public boolean isClass(){
186     return isClass;
187   }
188 
189   public void setName(String name) {
190     this.name = name;
191   }
192 
193   public String getName() {
194     return name;
195   }
196 
197   public void setType(String type) {
198     this.type = type;
199   }
200 
201   public String getType() {
202     return type;
203   }
204 
205   public void setFeature(String feature) {
206     this.feature = feature;
207   }
208 
209   public String getFeature() {
210     return feature;
211   }
212 
213   public void setWeighting(double weighting) {
214     this.weighting = weighting;
215   }
216 
217   public double getWeighting() {
218     return weighting;
219   }
220 
221   public java.util.List getValues() {
222     return values;
223   }
224 
225   public int getPosition() {
226     return position;
227   }
228 
229   public void setClass(boolean isClass) {
230     this.isClass = isClass;
231   }
232 
233   public void setValues(java.util.List values) {
234     this.values = values;
235   }
236 
237   public void setPosition(int position) {
238     this.position = position;
239   }
240 
241   /**
242    * This method reports whether the attribute is nominal, numeric or boolean.
243    *
244    * @return Attribute.NOMINAL, Attribute.NUMERIC or Attribute.BOOLEAN
245    */
246   public int semanticType() {
247     // Only nominal attributes specify values, and only numeric and nominal
248     // attributes specify feature, so this code is sufficient to distinguish
249     // the three kinds of attribute.
250     if (feature==null)
251       return BOOLEAN;
252     if (values==null)
253       return NUMERIC;
254     return NOMINAL;
255   }
256 
257   // These constants are used only for returning values from semanticType
258   public static final int NOMINAL=1;
259   public static final int NUMERIC=2;
260   public static final int BOOLEAN=3;
261 
262   boolean isClass = false;
263   private String name;
264   private String type;
265   private String feature;
266   private java.util.List values;
267   private int position;
268   // The SVMLightWrapper allows weighting for attributes to be specified in
269   // the configuration file, and those weightings are stored in this member.
270   // Weightings are (at time of writing) ignored by the Weka and Maxent
271   // wrappers.
272   private double weighting;
273 }