Source Code Cross Referenced for Attribute.java in  » Science » weka » weka » core » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Science » weka » weka.core 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         *    This program is free software; you can redistribute it and/or modify
0003:         *    it under the terms of the GNU General Public License as published by
0004:         *    the Free Software Foundation; either version 2 of the License, or
0005:         *    (at your option) any later version.
0006:         *
0007:         *    This program is distributed in the hope that it will be useful,
0008:         *    but WITHOUT ANY WARRANTY; without even the implied warranty of
0009:         *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0010:         *    GNU General Public License for more details.
0011:         *
0012:         *    You should have received a copy of the GNU General Public License
0013:         *    along with this program; if not, write to the Free Software
0014:         *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
0015:         */
0016:
0017:        /*
0018:         *    Attribute.java
0019:         *    Copyright (C) 1999 University of Waikato, Hamilton, New Zealand
0020:         *
0021:         */
0022:
0023:        package weka.core;
0024:
0025:        import java.io.Serializable;
0026:        import java.text.ParseException;
0027:        import java.text.SimpleDateFormat;
0028:        import java.util.Date;
0029:        import java.util.Enumeration;
0030:        import java.util.Hashtable;
0031:        import java.util.Properties;
0032:        import java.io.StreamTokenizer;
0033:        import java.io.StringReader;
0034:        import java.io.IOException;
0035:
0036:        /** 
0037:         * Class for handling an attribute. Once an attribute has been created,
0038:         * it can't be changed. <p>
0039:         *
0040:         * The following attribute types are supported:
0041:         * <ul>
0042:         *    <li> numeric: <br/>
0043:         *         This type of attribute represents a floating-point number.
0044:         *    </li>
0045:         *    <li> nominal: <br/>
0046:         *         This type of attribute represents a fixed set of nominal values.
0047:         *    </li>
0048:         *    <li> string: <br/>
0049:         *         This type of attribute represents a dynamically expanding set of
0050:         *         nominal values. Usually used in text classification.
0051:         *    </li>
0052:         *    <li> date: <br/>
0053:         *         This type of attribute represents a date, internally represented as 
0054:         *         floating-point number storing the milliseconds since January 1, 
0055:         *         1970, 00:00:00 GMT. The string representation of the date must be
0056:         *         <a href="http://www.iso.org/iso/en/prods-services/popstds/datesandtime.html" target="_blank">
0057:         *         ISO-8601</a> compliant, the default is <code>yyyy-MM-dd'T'HH:mm:ss</code>.
0058:         *    </li>
0059:         *    <li> relational: <br/>
0060:         *         This type of attribute can contain other attributes and is, e.g., 
0061:         *         used for representing Multi-Instance data. (Multi-Instance data
0062:         *         consists of a nominal attribute containing the bag-id, then a 
0063:         *         relational attribute with all the attributes of the bag, and 
0064:         *         finally the class attribute.)
0065:         *    </li>
0066:         * </ul>
0067:         * 
0068:         * Typical usage (code from the main() method of this class): <p>
0069:         *
0070:         * <code>
0071:         * ... <br>
0072:         *
0073:         * // Create numeric attributes "length" and "weight" <br>
0074:         * Attribute length = new Attribute("length"); <br>
0075:         * Attribute weight = new Attribute("weight"); <br><br>
0076:         * 
0077:         * // Create vector to hold nominal values "first", "second", "third" <br>
0078:         * FastVector my_nominal_values = new FastVector(3); <br>
0079:         * my_nominal_values.addElement("first"); <br>
0080:         * my_nominal_values.addElement("second"); <br>
0081:         * my_nominal_values.addElement("third"); <br><br>
0082:         *
0083:         * // Create nominal attribute "position" <br>
0084:         * Attribute position = new Attribute("position", my_nominal_values);<br>
0085:         *
0086:         * ... <br>
0087:         * </code><p>
0088:         *
0089:         * @author Eibe Frank (eibe@cs.waikato.ac.nz)
0090:         * @version $Revision: 1.44 $
0091:         */
0092:        public class Attribute implements  Copyable, Serializable {
0093:
0094:            /** for serialization */
0095:            static final long serialVersionUID = -742180568732916383L;
0096:
0097:            /** Constant set for numeric attributes. */
0098:            public static final int NUMERIC = 0;
0099:
0100:            /** Constant set for nominal attributes. */
0101:            public static final int NOMINAL = 1;
0102:
0103:            /** Constant set for attributes with string values. */
0104:            public static final int STRING = 2;
0105:
0106:            /** Constant set for attributes with date values. */
0107:            public static final int DATE = 3;
0108:
0109:            /** Constant set for relation-valued attributes. */
0110:            public static final int RELATIONAL = 4;
0111:
0112:            /** Constant set for symbolic attributes. */
0113:            public static final int ORDERING_SYMBOLIC = 0;
0114:
0115:            /** Constant set for ordered attributes. */
0116:            public static final int ORDERING_ORDERED = 1;
0117:
0118:            /** Constant set for modulo-ordered attributes. */
0119:            public static final int ORDERING_MODULO = 2;
0120:
0121:            /** The keyword used to denote the start of an arff attribute declaration */
0122:            public final static String ARFF_ATTRIBUTE = "@attribute";
0123:
0124:            /** A keyword used to denote a numeric attribute */
0125:            public final static String ARFF_ATTRIBUTE_INTEGER = "integer";
0126:
0127:            /** A keyword used to denote a numeric attribute */
0128:            public final static String ARFF_ATTRIBUTE_REAL = "real";
0129:
0130:            /** A keyword used to denote a numeric attribute */
0131:            public final static String ARFF_ATTRIBUTE_NUMERIC = "numeric";
0132:
0133:            /** The keyword used to denote a string attribute */
0134:            public final static String ARFF_ATTRIBUTE_STRING = "string";
0135:
0136:            /** The keyword used to denote a date attribute */
0137:            public final static String ARFF_ATTRIBUTE_DATE = "date";
0138:
0139:            /** The keyword used to denote a relation-valued attribute */
0140:            public final static String ARFF_ATTRIBUTE_RELATIONAL = "relational";
0141:
0142:            /** The keyword used to denote the end of the declaration of a subrelation */
0143:            public final static String ARFF_END_SUBRELATION = "@end";
0144:
0145:            /** Strings longer than this will be stored compressed. */
0146:            private static final int STRING_COMPRESS_THRESHOLD = 200;
0147:
0148:            /** The attribute's name. */
0149:            private/*@ spec_public non_null @*/String m_Name;
0150:
0151:            /** The attribute's type. */
0152:            private/*@ spec_public @*/int m_Type;
0153:            /*@ invariant m_Type == NUMERIC || 
0154:                          m_Type == DATE || 
0155:                          m_Type == STRING || 
0156:                          m_Type == NOMINAL ||
0157:                          m_Type == RELATIONAL;
0158:             */
0159:
0160:            /** The attribute's values (if nominal or string). */
0161:            private/*@ spec_public @*/FastVector m_Values;
0162:
0163:            /** Mapping of values to indices (if nominal or string). */
0164:            private Hashtable m_Hashtable;
0165:
0166:            /** The header information for a relation-valued attribute. */
0167:            private Instances m_Header;
0168:
0169:            /** Date format specification for date attributes */
0170:            private SimpleDateFormat m_DateFormat;
0171:
0172:            /** The attribute's index. */
0173:            private/*@ spec_public @*/int m_Index;
0174:
0175:            /** The attribute's metadata. */
0176:            private ProtectedProperties m_Metadata;
0177:
0178:            /** The attribute's ordering. */
0179:            private int m_Ordering;
0180:
0181:            /** Whether the attribute is regular. */
0182:            private boolean m_IsRegular;
0183:
0184:            /** Whether the attribute is averagable. */
0185:            private boolean m_IsAveragable;
0186:
0187:            /** Whether the attribute has a zeropoint. */
0188:            private boolean m_HasZeropoint;
0189:
0190:            /** The attribute's weight. */
0191:            private double m_Weight;
0192:
0193:            /** The attribute's lower numeric bound. */
0194:            private double m_LowerBound;
0195:
0196:            /** Whether the lower bound is open. */
0197:            private boolean m_LowerBoundIsOpen;
0198:
0199:            /** The attribute's upper numeric bound. */
0200:            private double m_UpperBound;
0201:
0202:            /** Whether the upper bound is open */
0203:            private boolean m_UpperBoundIsOpen;
0204:
0205:            /**
0206:             * Constructor for a numeric attribute.
0207:             *
0208:             * @param attributeName the name for the attribute
0209:             */
0210:            //@ requires attributeName != null;
0211:            //@ ensures  m_Name == attributeName;
0212:            public Attribute(String attributeName) {
0213:
0214:                this (attributeName, new ProtectedProperties(new Properties()));
0215:            }
0216:
0217:            /**
0218:             * Constructor for a numeric attribute, where metadata is supplied.
0219:             *
0220:             * @param attributeName the name for the attribute
0221:             * @param metadata the attribute's properties
0222:             */
0223:            //@ requires attributeName != null;
0224:            //@ requires metadata != null;
0225:            //@ ensures  m_Name == attributeName;
0226:            public Attribute(String attributeName, ProtectedProperties metadata) {
0227:
0228:                m_Name = attributeName;
0229:                m_Index = -1;
0230:                m_Values = null;
0231:                m_Hashtable = null;
0232:                m_Header = null;
0233:                m_Type = NUMERIC;
0234:                setMetadata(metadata);
0235:            }
0236:
0237:            /**
0238:             * Constructor for a date attribute.
0239:             *
0240:             * @param attributeName the name for the attribute
0241:             * @param dateFormat a string suitable for use with
0242:             * SimpleDateFormatter for parsing dates.
0243:             */
0244:            //@ requires attributeName != null;
0245:            //@ requires dateFormat != null;
0246:            //@ ensures  m_Name == attributeName;
0247:            public Attribute(String attributeName, String dateFormat) {
0248:
0249:                this (attributeName, dateFormat, new ProtectedProperties(
0250:                        new Properties()));
0251:            }
0252:
0253:            /**
0254:             * Constructor for a date attribute, where metadata is supplied.
0255:             *
0256:             * @param attributeName the name for the attribute
0257:             * @param dateFormat a string suitable for use with
0258:             * SimpleDateFormatter for parsing dates.
0259:             * @param metadata the attribute's properties
0260:             */
0261:            //@ requires attributeName != null;
0262:            //@ requires dateFormat != null;
0263:            //@ requires metadata != null;
0264:            //@ ensures  m_Name == attributeName;
0265:            public Attribute(String attributeName, String dateFormat,
0266:                    ProtectedProperties metadata) {
0267:
0268:                m_Name = attributeName;
0269:                m_Index = -1;
0270:                m_Values = null;
0271:                m_Hashtable = null;
0272:                m_Header = null;
0273:                m_Type = DATE;
0274:                if (dateFormat != null) {
0275:                    m_DateFormat = new SimpleDateFormat(dateFormat);
0276:                } else {
0277:                    m_DateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
0278:                }
0279:                m_DateFormat.setLenient(false);
0280:                setMetadata(metadata);
0281:            }
0282:
0283:            /**
0284:             * Constructor for nominal attributes and string attributes.
0285:             * If a null vector of attribute values is passed to the method,
0286:             * the attribute is assumed to be a string.
0287:             *
0288:             * @param attributeName the name for the attribute
0289:             * @param attributeValues a vector of strings denoting the 
0290:             * attribute values. Null if the attribute is a string attribute.
0291:             */
0292:            //@ requires attributeName != null;
0293:            //@ ensures  m_Name == attributeName;
0294:            public Attribute(String attributeName, FastVector attributeValues) {
0295:
0296:                this (attributeName, attributeValues, new ProtectedProperties(
0297:                        new Properties()));
0298:            }
0299:
0300:            /**
0301:             * Constructor for nominal attributes and string attributes, where
0302:             * metadata is supplied. If a null vector of attribute values is passed
0303:             * to the method, the attribute is assumed to be a string.
0304:             *
0305:             * @param attributeName the name for the attribute
0306:             * @param attributeValues a vector of strings denoting the 
0307:             * attribute values. Null if the attribute is a string attribute.
0308:             * @param metadata the attribute's properties
0309:             */
0310:            //@ requires attributeName != null;
0311:            //@ requires metadata != null;
0312:            /*@ ensures  m_Name == attributeName;
0313:                ensures  m_Index == -1;
0314:                ensures  attributeValues == null && m_Type == STRING
0315:                      || attributeValues != null && m_Type == NOMINAL 
0316:                            && m_Values.size() == attributeValues.size();
0317:                signals (IllegalArgumentException ex) 
0318:                           (* if duplicate strings in attributeValues *);
0319:             */
0320:            public Attribute(String attributeName, FastVector attributeValues,
0321:                    ProtectedProperties metadata) {
0322:
0323:                m_Name = attributeName;
0324:                m_Index = -1;
0325:                if (attributeValues == null) {
0326:                    m_Values = new FastVector();
0327:                    m_Hashtable = new Hashtable();
0328:                    m_Header = null;
0329:                    m_Type = STRING;
0330:                } else {
0331:                    m_Values = new FastVector(attributeValues.size());
0332:                    m_Hashtable = new Hashtable(attributeValues.size());
0333:                    m_Header = null;
0334:                    for (int i = 0; i < attributeValues.size(); i++) {
0335:                        Object store = attributeValues.elementAt(i);
0336:                        if (((String) store).length() > STRING_COMPRESS_THRESHOLD) {
0337:                            try {
0338:                                store = new SerializedObject(attributeValues
0339:                                        .elementAt(i), true);
0340:                            } catch (Exception ex) {
0341:                                System.err
0342:                                        .println("Couldn't compress nominal attribute value -"
0343:                                                + " storing uncompressed.");
0344:                            }
0345:                        }
0346:                        if (m_Hashtable.containsKey(store)) {
0347:                            throw new IllegalArgumentException(
0348:                                    "A nominal attribute (" + attributeName
0349:                                            + ") cannot"
0350:                                            + " have duplicate labels ("
0351:                                            + store + ").");
0352:                        }
0353:                        m_Values.addElement(store);
0354:                        m_Hashtable.put(store, new Integer(i));
0355:                    }
0356:                    m_Type = NOMINAL;
0357:                }
0358:                setMetadata(metadata);
0359:            }
0360:
0361:            /**
0362:             * Constructor for relation-valued attributes.
0363:             *
0364:             * @param attributeName the name for the attribute
0365:             * @param header an Instances object specifying the header of the relation.
0366:             */
0367:            public Attribute(String attributeName, Instances header) {
0368:
0369:                this (attributeName, header, new ProtectedProperties(
0370:                        new Properties()));
0371:            }
0372:
0373:            /**
0374:             * Constructor for relation-valued attributes.
0375:             *
0376:             * @param attributeName the name for the attribute
0377:             * @param header an Instances object specifying the header of the relation.
0378:             * @param metadata the attribute's properties
0379:             */
0380:            public Attribute(String attributeName, Instances header,
0381:                    ProtectedProperties metadata) {
0382:
0383:                if (header.numInstances() > 0) {
0384:                    throw new IllegalArgumentException(
0385:                            "Header for relation-valued "
0386:                                    + "attribute should not contain "
0387:                                    + "any instances");
0388:                }
0389:                m_Name = attributeName;
0390:                m_Index = -1;
0391:                m_Values = new FastVector();
0392:                m_Hashtable = new Hashtable();
0393:                m_Header = header;
0394:                m_Type = RELATIONAL;
0395:                setMetadata(metadata);
0396:            }
0397:
0398:            /**
0399:             * Produces a shallow copy of this attribute.
0400:             *
0401:             * @return a copy of this attribute with the same index
0402:             */
0403:            //@ also ensures \result instanceof Attribute;
0404:            public/*@ pure non_null @*/Object copy() {
0405:
0406:                Attribute copy = new Attribute(m_Name);
0407:
0408:                copy.m_Index = m_Index;
0409:                copy.m_Type = m_Type;
0410:                copy.m_Values = m_Values;
0411:                copy.m_Hashtable = m_Hashtable;
0412:                copy.m_DateFormat = m_DateFormat;
0413:                copy.m_Header = m_Header;
0414:                copy.setMetadata(m_Metadata);
0415:
0416:                return copy;
0417:            }
0418:
0419:            /**
0420:             * Returns an enumeration of all the attribute's values if the
0421:             * attribute is nominal, string, or relation-valued, null otherwise.
0422:             *
0423:             * @return enumeration of all the attribute's values
0424:             */
0425:            public final/*@ pure @*/Enumeration enumerateValues() {
0426:
0427:                if (isNominal() || isString()) {
0428:                    final Enumeration ee = m_Values.elements();
0429:                    return new Enumeration() {
0430:                        public boolean hasMoreElements() {
0431:                            return ee.hasMoreElements();
0432:                        }
0433:
0434:                        public Object nextElement() {
0435:                            Object oo = ee.nextElement();
0436:                            if (oo instanceof  SerializedObject) {
0437:                                return ((SerializedObject) oo).getObject();
0438:                            } else {
0439:                                return oo;
0440:                            }
0441:                        }
0442:                    };
0443:                }
0444:                return null;
0445:            }
0446:
0447:            /**
0448:             * Tests if given attribute is equal to this attribute.
0449:             *
0450:             * @param other the Object to be compared to this attribute
0451:             * @return true if the given attribute is equal to this attribute
0452:             */
0453:            public final/*@ pure @*/boolean equals(Object other) {
0454:
0455:                if ((other == null)
0456:                        || !(other.getClass().equals(this .getClass()))) {
0457:                    return false;
0458:                }
0459:                Attribute att = (Attribute) other;
0460:                if (!m_Name.equals(att.m_Name)) {
0461:                    return false;
0462:                }
0463:                if (isNominal() && att.isNominal()) {
0464:                    if (m_Values.size() != att.m_Values.size()) {
0465:                        return false;
0466:                    }
0467:                    for (int i = 0; i < m_Values.size(); i++) {
0468:                        if (!m_Values.elementAt(i).equals(
0469:                                att.m_Values.elementAt(i))) {
0470:                            return false;
0471:                        }
0472:                    }
0473:                    return true;
0474:                }
0475:                if (isRelationValued() && att.isRelationValued()) {
0476:                    if (!m_Header.equalHeaders(att.m_Header)) {
0477:                        return false;
0478:                    }
0479:                    return true;
0480:                }
0481:                return (type() == att.type());
0482:            }
0483:
0484:            /**
0485:             * Returns the index of this attribute.
0486:             *
0487:             * @return the index of this attribute
0488:             */
0489:            //@ ensures \result == m_Index;
0490:            public final/*@ pure @*/int index() {
0491:
0492:                return m_Index;
0493:            }
0494:
0495:            /**
0496:             * Returns the index of a given attribute value. (The index of
0497:             * the first occurence of this value.)
0498:             *
0499:             * @param value the value for which the index is to be returned
0500:             * @return the index of the given attribute value if attribute
0501:             * is nominal or a string, -1 if it is not or the value 
0502:             * can't be found
0503:             */
0504:            public final int indexOfValue(String value) {
0505:
0506:                if (!isNominal() && !isString())
0507:                    return -1;
0508:                Object store = value;
0509:                if (value.length() > STRING_COMPRESS_THRESHOLD) {
0510:                    try {
0511:                        store = new SerializedObject(value, true);
0512:                    } catch (Exception ex) {
0513:                        System.err
0514:                                .println("Couldn't compress string attribute value -"
0515:                                        + " searching uncompressed.");
0516:                    }
0517:                }
0518:                Integer val = (Integer) m_Hashtable.get(store);
0519:                if (val == null)
0520:                    return -1;
0521:                else
0522:                    return val.intValue();
0523:            }
0524:
0525:            /**
0526:             * Test if the attribute is nominal.
0527:             *
0528:             * @return true if the attribute is nominal
0529:             */
0530:            //@ ensures \result <==> (m_Type == NOMINAL);
0531:            public final/*@ pure @*/boolean isNominal() {
0532:
0533:                return (m_Type == NOMINAL);
0534:            }
0535:
0536:            /**
0537:             * Tests if the attribute is numeric.
0538:             *
0539:             * @return true if the attribute is numeric
0540:             */
0541:            //@ ensures \result <==> ((m_Type == NUMERIC) || (m_Type == DATE));
0542:            public final/*@ pure @*/boolean isNumeric() {
0543:
0544:                return ((m_Type == NUMERIC) || (m_Type == DATE));
0545:            }
0546:
0547:            /**
0548:             * Tests if the attribute is relation valued.
0549:             *
0550:             * @return true if the attribute is relation valued
0551:             */
0552:            //@ ensures \result <==> (m_Type == RELATIONAL);
0553:            public final/*@ pure @*/boolean isRelationValued() {
0554:
0555:                return (m_Type == RELATIONAL);
0556:            }
0557:
0558:            /**
0559:             * Tests if the attribute is a string.
0560:             *
0561:             * @return true if the attribute is a string
0562:             */
0563:            //@ ensures \result <==> (m_Type == STRING);
0564:            public final/*@ pure @*/boolean isString() {
0565:
0566:                return (m_Type == STRING);
0567:            }
0568:
0569:            /**
0570:             * Tests if the attribute is a date type.
0571:             *
0572:             * @return true if the attribute is a date type
0573:             */
0574:            //@ ensures \result <==> (m_Type == DATE);
0575:            public final/*@ pure @*/boolean isDate() {
0576:
0577:                return (m_Type == DATE);
0578:            }
0579:
0580:            /**
0581:             * Returns the attribute's name.
0582:             *
0583:             * @return the attribute's name as a string
0584:             */
0585:            //@ ensures \result == m_Name;
0586:            public final/*@ pure @*/String name() {
0587:
0588:                return m_Name;
0589:            }
0590:
0591:            /**
0592:             * Returns the number of attribute values. Returns 0 for 
0593:             * attributes that are not either nominal, string, or
0594:             * relation-valued.
0595:             *
0596:             * @return the number of attribute values
0597:             */
0598:            public final/*@ pure @*/int numValues() {
0599:
0600:                if (!isNominal() && !isString() && !isRelationValued()) {
0601:                    return 0;
0602:                } else {
0603:                    return m_Values.size();
0604:                }
0605:            }
0606:
0607:            /**
0608:             * Returns a description of this attribute in ARFF format. Quotes
0609:             * strings if they contain whitespace characters, or if they
0610:             * are a question mark.
0611:             *
0612:             * @return a description of this attribute as a string
0613:             */
0614:            public final String toString() {
0615:
0616:                StringBuffer text = new StringBuffer();
0617:
0618:                text.append(ARFF_ATTRIBUTE).append(" ").append(
0619:                        Utils.quote(m_Name)).append(" ");
0620:                switch (m_Type) {
0621:                case NOMINAL:
0622:                    text.append('{');
0623:                    Enumeration enu = enumerateValues();
0624:                    while (enu.hasMoreElements()) {
0625:                        text.append(Utils.quote((String) enu.nextElement()));
0626:                        if (enu.hasMoreElements())
0627:                            text.append(',');
0628:                    }
0629:                    text.append('}');
0630:                    break;
0631:                case NUMERIC:
0632:                    text.append(ARFF_ATTRIBUTE_NUMERIC);
0633:                    break;
0634:                case STRING:
0635:                    text.append(ARFF_ATTRIBUTE_STRING);
0636:                    break;
0637:                case DATE:
0638:                    text.append(ARFF_ATTRIBUTE_DATE).append(" ").append(
0639:                            Utils.quote(m_DateFormat.toPattern()));
0640:                    break;
0641:                case RELATIONAL:
0642:                    text.append(ARFF_ATTRIBUTE_RELATIONAL).append("\n");
0643:                    Enumeration enm = m_Header.enumerateAttributes();
0644:                    while (enm.hasMoreElements()) {
0645:                        text.append(enm.nextElement()).append("\n");
0646:                    }
0647:                    text.append(ARFF_END_SUBRELATION).append(" ").append(
0648:                            Utils.quote(m_Name));
0649:                    break;
0650:                default:
0651:                    text.append("UNKNOWN");
0652:                    break;
0653:                }
0654:                return text.toString();
0655:            }
0656:
0657:            /**
0658:             * Returns the attribute's type as an integer.
0659:             *
0660:             * @return the attribute's type.
0661:             */
0662:            //@ ensures \result == m_Type;
0663:            public final/*@ pure @*/int type() {
0664:
0665:                return m_Type;
0666:            }
0667:
0668:            /**
0669:             * Returns the Date format pattern in case this attribute is of type DATE,
0670:             * otherwise an empty string.
0671:             * 
0672:             * @return the date format pattern
0673:             * @see SimpleDateFormat
0674:             */
0675:            public final String getDateFormat() {
0676:                if (isDate())
0677:                    return m_DateFormat.toPattern();
0678:                else
0679:                    return "";
0680:            }
0681:
0682:            /**
0683:             * Returns a value of a nominal or string attribute.  Returns an
0684:             * empty string if the attribute is neither a string nor a nominal
0685:             * attribute.
0686:             *
0687:             * @param valIndex the value's index
0688:             * @return the attribute's value as a string
0689:             */
0690:            public final/*@ non_null pure @*/String value(int valIndex) {
0691:
0692:                if (!isNominal() && !isString()) {
0693:                    return "";
0694:                } else {
0695:                    Object val = m_Values.elementAt(valIndex);
0696:
0697:                    // If we're storing strings compressed, uncompress it.
0698:                    if (val instanceof  SerializedObject) {
0699:                        val = ((SerializedObject) val).getObject();
0700:                    }
0701:                    return (String) val;
0702:                }
0703:            }
0704:
0705:            /**
0706:             * Returns the header info for a relation-valued attribute,
0707:             * null if the attribute is not relation-valued.
0708:             *
0709:             * @return the attribute's value as an Instances object
0710:             */
0711:            public final/*@ non_null pure @*/Instances relation() {
0712:
0713:                if (!isRelationValued()) {
0714:                    return null;
0715:                } else {
0716:                    return m_Header;
0717:                }
0718:            }
0719:
0720:            /**
0721:             * Returns a value of a relation-valued attribute. Returns
0722:             * null if the attribute is not relation-valued.
0723:             *
0724:             * @param valIndex the value's index
0725:             * @return the attribute's value as an Instances object
0726:             */
0727:            public final/*@ non_null pure @*/Instances relation(int valIndex) {
0728:
0729:                if (!isRelationValued()) {
0730:                    return null;
0731:                } else {
0732:                    return (Instances) m_Values.elementAt(valIndex);
0733:                }
0734:            }
0735:
0736:            /**
0737:             * Constructor for a numeric attribute with a particular index.
0738:             *
0739:             * @param attributeName the name for the attribute
0740:             * @param index the attribute's index
0741:             */
0742:            //@ requires attributeName != null;
0743:            //@ requires index >= 0;
0744:            //@ ensures  m_Name == attributeName;
0745:            //@ ensures  m_Index == index;
0746:            public Attribute(String attributeName, int index) {
0747:
0748:                this (attributeName);
0749:                m_Index = index;
0750:            }
0751:
0752:            /**
0753:             * Constructor for date attributes with a particular index.
0754:             *
0755:             * @param attributeName the name for the attribute
0756:             * @param dateFormat a string suitable for use with
0757:             * SimpleDateFormatter for parsing dates.  Null for a default format
0758:             * string.
0759:             * @param index the attribute's index
0760:             */
0761:            //@ requires attributeName != null;
0762:            //@ requires index >= 0;
0763:            //@ ensures  m_Name == attributeName;
0764:            //@ ensures  m_Index == index;
0765:            public Attribute(String attributeName, String dateFormat, int index) {
0766:
0767:                this (attributeName, dateFormat);
0768:                m_Index = index;
0769:            }
0770:
0771:            /**
0772:             * Constructor for nominal attributes and string attributes with
0773:             * a particular index.
0774:             * If a null vector of attribute values is passed to the method,
0775:             * the attribute is assumed to be a string.
0776:             *
0777:             * @param attributeName the name for the attribute
0778:             * @param attributeValues a vector of strings denoting the attribute values.
0779:             * Null if the attribute is a string attribute.
0780:             * @param index the attribute's index
0781:             */
0782:            //@ requires attributeName != null;
0783:            //@ requires index >= 0;
0784:            //@ ensures  m_Name == attributeName;
0785:            //@ ensures  m_Index == index;
0786:            public Attribute(String attributeName, FastVector attributeValues,
0787:                    int index) {
0788:
0789:                this (attributeName, attributeValues);
0790:                m_Index = index;
0791:            }
0792:
0793:            /**
0794:             * Constructor for a relation-valued attribute with a particular index.
0795:             *
0796:             * @param attributeName the name for the attribute
0797:             * @param header the header information for this attribute
0798:             * @param index the attribute's index
0799:             */
0800:            //@ requires attributeName != null;
0801:            //@ requires index >= 0;
0802:            //@ ensures  m_Name == attributeName;
0803:            //@ ensures  m_Index == index;
0804:            public Attribute(String attributeName, Instances header, int index) {
0805:
0806:                this (attributeName, header);
0807:                m_Index = index;
0808:            }
0809:
0810:            /**
0811:             * Adds a string value to the list of valid strings for attributes
0812:             * of type STRING and returns the index of the string.
0813:             *
0814:             * @param value The string value to add
0815:             * @return the index assigned to the string, or -1 if the attribute is not
0816:             * of type Attribute.STRING 
0817:             */
0818:            /*@ requires value != null;
0819:                ensures  isString() && 0 <= \result && \result < m_Values.size() ||
0820:                       ! isString() && \result == -1;
0821:             */
0822:            public int addStringValue(String value) {
0823:
0824:                if (!isString()) {
0825:                    return -1;
0826:                }
0827:                Object store = value;
0828:
0829:                if (value.length() > STRING_COMPRESS_THRESHOLD) {
0830:                    try {
0831:                        store = new SerializedObject(value, true);
0832:                    } catch (Exception ex) {
0833:                        System.err
0834:                                .println("Couldn't compress string attribute value -"
0835:                                        + " storing uncompressed.");
0836:                    }
0837:                }
0838:                Integer index = (Integer) m_Hashtable.get(store);
0839:                if (index != null) {
0840:                    return index.intValue();
0841:                } else {
0842:                    int intIndex = m_Values.size();
0843:                    m_Values.addElement(store);
0844:                    m_Hashtable.put(store, new Integer(intIndex));
0845:                    return intIndex;
0846:                }
0847:            }
0848:
0849:            /**
0850:             * Adds a string value to the list of valid strings for attributes
0851:             * of type STRING and returns the index of the string. This method is
0852:             * more efficient than addStringValue(String) for long strings.
0853:             *
0854:             * @param src The Attribute containing the string value to add.
0855:             * @param index the index of the string value in the source attribute.
0856:             * @return the index assigned to the string, or -1 if the attribute is not
0857:             * of type Attribute.STRING 
0858:             */
0859:            /*@ requires src != null;
0860:                requires 0 <= index && index < src.m_Values.size();
0861:                ensures  isString() && 0 <= \result && \result < m_Values.size() ||
0862:                       ! isString() && \result == -1;
0863:             */
0864:            public int addStringValue(Attribute src, int index) {
0865:
0866:                if (!isString()) {
0867:                    return -1;
0868:                }
0869:                Object store = src.m_Values.elementAt(index);
0870:                Integer oldIndex = (Integer) m_Hashtable.get(store);
0871:                if (oldIndex != null) {
0872:                    return oldIndex.intValue();
0873:                } else {
0874:                    int intIndex = m_Values.size();
0875:                    m_Values.addElement(store);
0876:                    m_Hashtable.put(store, new Integer(intIndex));
0877:                    return intIndex;
0878:                }
0879:            }
0880:
0881:            /**
0882:             * Adds a relation to a relation-valued attribute.
0883:             *
0884:             * @param value The value to add
0885:             * @return the index assigned to the value, or -1 if the attribute is not
0886:             * of type Attribute.RELATIONAL 
0887:             */
0888:            public int addRelation(Instances value) {
0889:
0890:                if (!isRelationValued()) {
0891:                    return -1;
0892:                }
0893:                if (!m_Header.equalHeaders(value)) {
0894:                    throw new IllegalArgumentException(
0895:                            "Incompatible value for "
0896:                                    + "relation-valued attribute.");
0897:                }
0898:                Integer index = (Integer) m_Hashtable.get(value);
0899:                if (index != null) {
0900:                    return index.intValue();
0901:                } else {
0902:                    int intIndex = m_Values.size();
0903:                    m_Values.addElement(value);
0904:                    m_Hashtable.put(value, new Integer(intIndex));
0905:                    return intIndex;
0906:                }
0907:            }
0908:
0909:            /**
0910:             * Adds an attribute value. Creates a fresh list of attribute
0911:             * values before adding it.
0912:             *
0913:             * @param value the attribute value
0914:             */
0915:            final void addValue(String value) {
0916:
0917:                m_Values = (FastVector) m_Values.copy();
0918:                m_Hashtable = (Hashtable) m_Hashtable.clone();
0919:                forceAddValue(value);
0920:            }
0921:
0922:            /**
0923:             * Produces a shallow copy of this attribute with a new name.
0924:             *
0925:             * @param newName the name of the new attribute
0926:             * @return a copy of this attribute with the same index
0927:             */
0928:            //@ requires newName != null;
0929:            //@ ensures \result.m_Name  == newName;
0930:            //@ ensures \result.m_Index == m_Index;
0931:            //@ ensures \result.m_Type  == m_Type;
0932:            public final/*@ pure non_null @*/Attribute copy(String newName) {
0933:
0934:                Attribute copy = new Attribute(newName);
0935:
0936:                copy.m_Index = m_Index;
0937:                copy.m_DateFormat = m_DateFormat;
0938:                copy.m_Type = m_Type;
0939:                copy.m_Values = m_Values;
0940:                copy.m_Hashtable = m_Hashtable;
0941:                copy.m_Header = m_Header;
0942:                copy.setMetadata(m_Metadata);
0943:
0944:                return copy;
0945:            }
0946:
0947:            /**
0948:             * Removes a value of a nominal, string, or relation-valued
0949:             * attribute. Creates a fresh list of attribute values before
0950:             * removing it.
0951:             *
0952:             * @param index the value's index
0953:             * @throws IllegalArgumentException if the attribute is not 
0954:             * of the correct type
0955:             */
0956:            //@ requires isNominal() || isString() || isRelationValued();
0957:            //@ requires 0 <= index && index < m_Values.size();
0958:            final void delete(int index) {
0959:
0960:                if (!isNominal() && !isString() && !isRelationValued())
0961:                    throw new IllegalArgumentException(
0962:                            "Can only remove value of "
0963:                                    + "nominal, string or relation-"
0964:                                    + " valued attribute!");
0965:                else {
0966:                    m_Values = (FastVector) m_Values.copy();
0967:                    m_Values.removeElementAt(index);
0968:                    if (!isRelationValued()) {
0969:                        Hashtable hash = new Hashtable(m_Hashtable.size());
0970:                        Enumeration enu = m_Hashtable.keys();
0971:                        while (enu.hasMoreElements()) {
0972:                            Object string = enu.nextElement();
0973:                            Integer valIndexObject = (Integer) m_Hashtable
0974:                                    .get(string);
0975:                            int valIndex = valIndexObject.intValue();
0976:                            if (valIndex > index) {
0977:                                hash.put(string, new Integer(valIndex - 1));
0978:                            } else if (valIndex < index) {
0979:                                hash.put(string, valIndexObject);
0980:                            }
0981:                        }
0982:                        m_Hashtable = hash;
0983:                    }
0984:                }
0985:            }
0986:
0987:            /**
0988:             * Adds an attribute value.
0989:             *
0990:             * @param value the attribute value
0991:             */
0992:            //@ requires value != null;
0993:            //@ ensures  m_Values.size() == \old(m_Values.size()) + 1;
0994:            final void forceAddValue(String value) {
0995:
0996:                Object store = value;
0997:                if (value.length() > STRING_COMPRESS_THRESHOLD) {
0998:                    try {
0999:                        store = new SerializedObject(value, true);
1000:                    } catch (Exception ex) {
1001:                        System.err
1002:                                .println("Couldn't compress string attribute value -"
1003:                                        + " storing uncompressed.");
1004:                    }
1005:                }
1006:                m_Values.addElement(store);
1007:                m_Hashtable.put(store, new Integer(m_Values.size() - 1));
1008:            }
1009:
1010:            /**
1011:             * Sets the index of this attribute.
1012:             *
1013:             * @param index the index of this attribute
1014:             */
1015:            //@ requires 0 <= index;
1016:            //@ assignable m_Index;
1017:            //@ ensures m_Index == index;
1018:            final void setIndex(int index) {
1019:
1020:                m_Index = index;
1021:            }
1022:
1023:            /**
1024:             * Sets a value of a nominal attribute or string attribute.
1025:             * Creates a fresh list of attribute values before it is set.
1026:             *
1027:             * @param index the value's index
1028:             * @param string the value
1029:             * @throws IllegalArgumentException if the attribute is not nominal or 
1030:             * string.
1031:             */
1032:            //@ requires string != null;
1033:            //@ requires isNominal() || isString();
1034:            //@ requires 0 <= index && index < m_Values.size();
1035:            final void setValue(int index, String string) {
1036:
1037:                switch (m_Type) {
1038:                case NOMINAL:
1039:                case STRING:
1040:                    m_Values = (FastVector) m_Values.copy();
1041:                    m_Hashtable = (Hashtable) m_Hashtable.clone();
1042:                    Object store = string;
1043:                    if (string.length() > STRING_COMPRESS_THRESHOLD) {
1044:                        try {
1045:                            store = new SerializedObject(string, true);
1046:                        } catch (Exception ex) {
1047:                            System.err
1048:                                    .println("Couldn't compress string attribute value -"
1049:                                            + " storing uncompressed.");
1050:                        }
1051:                    }
1052:                    m_Hashtable.remove(m_Values.elementAt(index));
1053:                    m_Values.setElementAt(store, index);
1054:                    m_Hashtable.put(store, new Integer(index));
1055:                    break;
1056:                default:
1057:                    throw new IllegalArgumentException(
1058:                            "Can only set values for nominal"
1059:                                    + " or string attributes!");
1060:                }
1061:            }
1062:
1063:            /**
1064:             * Sets a value of a relation-valued attribute.
1065:             * Creates a fresh list of attribute values before it is set.
1066:             *
1067:             * @param index the value's index
1068:             * @param data the value
1069:             * @throws IllegalArgumentException if the attribute is not 
1070:             * relation-valued.
1071:             */
1072:            final void setValue(int index, Instances data) {
1073:
1074:                if (isRelationValued()) {
1075:                    if (!data.equalHeaders(m_Header)) {
1076:                        throw new IllegalArgumentException(
1077:                                "Can't set relational value. "
1078:                                        + "Headers not compatible.");
1079:                    }
1080:                    m_Values = (FastVector) m_Values.copy();
1081:                    m_Values.setElementAt(data, index);
1082:                } else {
1083:                    throw new IllegalArgumentException("Can only set value for"
1084:                            + " relation-valued attributes!");
1085:                }
1086:            }
1087:
1088:            /**
1089:             * Returns the given amount of milliseconds formatted according to the
1090:             * current Date format.
1091:             * 
1092:             * @param date 	the date, represented in milliseconds since 
1093:             * 			January 1, 1970, 00:00:00 GMT, to return as string
1094:             * @return 		the formatted date
1095:             */
1096:            //@ requires isDate();
1097:            public/*@pure@*/String formatDate(double date) {
1098:                switch (m_Type) {
1099:                case DATE:
1100:                    return m_DateFormat.format(new Date((long) date));
1101:                default:
1102:                    throw new IllegalArgumentException(
1103:                            "Can only format date values for date"
1104:                                    + " attributes!");
1105:                }
1106:            }
1107:
1108:            /**
1109:             * Parses the given String as Date, according to the current format and
1110:             * returns the corresponding amount of milliseconds.
1111:             * 
1112:             * @param string the date to parse
1113:             * @return the date in milliseconds since January 1, 1970, 00:00:00 GMT
1114:             * @throws ParseException if parsing fails
1115:             */
1116:            //@ requires isDate();
1117:            //@ requires string != null;
1118:            public double parseDate(String string) throws ParseException {
1119:                switch (m_Type) {
1120:                case DATE:
1121:                    long time = m_DateFormat.parse(string).getTime();
1122:                    // TODO put in a safety check here if we can't store the value in a double.
1123:                    return (double) time;
1124:                default:
1125:                    throw new IllegalArgumentException(
1126:                            "Can only parse date values for date"
1127:                                    + " attributes!");
1128:                }
1129:            }
1130:
1131:            /**
1132:             * Returns the properties supplied for this attribute.
1133:             *
1134:             * @return metadata for this attribute
1135:             */
1136:            public final/*@ pure @*/ProtectedProperties getMetadata() {
1137:
1138:                return m_Metadata;
1139:            }
1140:
1141:            /**
1142:             * Returns the ordering of the attribute. One of the following:
1143:             * 
1144:             * ORDERING_SYMBOLIC - attribute values should be treated as symbols.
1145:             * ORDERING_ORDERED  - attribute values have a global ordering.
1146:             * ORDERING_MODULO   - attribute values have an ordering which wraps.
1147:             *
1148:             * @return the ordering type of the attribute
1149:             */
1150:            public final/*@ pure @*/int ordering() {
1151:
1152:                return m_Ordering;
1153:            }
1154:
1155:            /**
1156:             * Returns whether the attribute values are equally spaced.
1157:             *
1158:             * @return whether the attribute is regular or not
1159:             */
1160:            public final/*@ pure @*/boolean isRegular() {
1161:
1162:                return m_IsRegular;
1163:            }
1164:
1165:            /**
1166:             * Returns whether the attribute can be averaged meaningfully.
1167:             *
1168:             * @return whether the attribute can be averaged or not
1169:             */
1170:            public final/*@ pure @*/boolean isAveragable() {
1171:
1172:                return m_IsAveragable;
1173:            }
1174:
1175:            /**
1176:             * Returns whether the attribute has a zeropoint and may be
1177:             * added meaningfully.
1178:             *
1179:             * @return whether the attribute has a zeropoint or not
1180:             */
1181:            public final/*@ pure @*/boolean hasZeropoint() {
1182:
1183:                return m_HasZeropoint;
1184:            }
1185:
1186:            /**
1187:             * Returns the attribute's weight.
1188:             *
1189:             * @return the attribute's weight as a double
1190:             */
1191:            public final/*@ pure @*/double weight() {
1192:
1193:                return m_Weight;
1194:            }
1195:
1196:            /**
1197:             * Sets the new attribute's weight
1198:             * 
1199:             * @param value	the new weight
1200:             */
1201:            public void setWeight(double value) {
1202:                Properties props;
1203:                Enumeration names;
1204:                String name;
1205:
1206:                m_Weight = value;
1207:
1208:                // generate new metadata object
1209:                props = new Properties();
1210:                names = m_Metadata.propertyNames();
1211:                while (names.hasMoreElements()) {
1212:                    name = (String) names.nextElement();
1213:                    if (!name.equals("weight"))
1214:                        props.setProperty(name, m_Metadata.getProperty(name));
1215:                }
1216:                props.setProperty("weight", "" + m_Weight);
1217:                m_Metadata = new ProtectedProperties(props);
1218:            }
1219:
1220:            /**
1221:             * Returns the lower bound of a numeric attribute.
1222:             *
1223:             * @return the lower bound of the specified numeric range
1224:             */
1225:            public final/*@ pure @*/double getLowerNumericBound() {
1226:
1227:                return m_LowerBound;
1228:            }
1229:
1230:            /**
1231:             * Returns whether the lower numeric bound of the attribute is open.
1232:             *
1233:             * @return whether the lower numeric bound is open or not (closed)
1234:             */
1235:            public final/*@ pure @*/boolean lowerNumericBoundIsOpen() {
1236:
1237:                return m_LowerBoundIsOpen;
1238:            }
1239:
1240:            /**
1241:             * Returns the upper bound of a numeric attribute.
1242:             *
1243:             * @return the upper bound of the specified numeric range
1244:             */
1245:            public final/*@ pure @*/double getUpperNumericBound() {
1246:
1247:                return m_UpperBound;
1248:            }
1249:
1250:            /**
1251:             * Returns whether the upper numeric bound of the attribute is open.
1252:             *
1253:             * @return whether the upper numeric bound is open or not (closed)
1254:             */
1255:            public final/*@ pure @*/boolean upperNumericBoundIsOpen() {
1256:
1257:                return m_UpperBoundIsOpen;
1258:            }
1259:
1260:            /**
1261:             * Determines whether a value lies within the bounds of the attribute.
1262:             *
1263:             * @param value the value to check
1264:             * @return whether the value is in range
1265:             */
1266:            public final/*@ pure @*/boolean isInRange(double value) {
1267:
1268:                // dates and missing values are a special case 
1269:                if (m_Type == DATE || value == Instance.missingValue())
1270:                    return true;
1271:                if (m_Type != NUMERIC) {
1272:                    // do label range check
1273:                    int intVal = (int) value;
1274:                    if (intVal < 0 || intVal >= m_Hashtable.size())
1275:                        return false;
1276:                } else {
1277:                    // do numeric bounds check
1278:                    if (m_LowerBoundIsOpen) {
1279:                        if (value <= m_LowerBound)
1280:                            return false;
1281:                    } else {
1282:                        if (value < m_LowerBound)
1283:                            return false;
1284:                    }
1285:                    if (m_UpperBoundIsOpen) {
1286:                        if (value >= m_UpperBound)
1287:                            return false;
1288:                    } else {
1289:                        if (value > m_UpperBound)
1290:                            return false;
1291:                    }
1292:                }
1293:                return true;
1294:            }
1295:
1296:            /**
1297:             * Sets the metadata for the attribute. Processes the strings stored in the
1298:             * metadata of the attribute so that the properties can be set up for the
1299:             * easy-access metadata methods. Any strings sought that are omitted will
1300:             * cause default values to be set.
1301:             * 
1302:             * The following properties are recognised:
1303:             * ordering, averageable, zeropoint, regular, weight, and range.
1304:             *
1305:             * All other properties can be queried and handled appropriately by classes
1306:             * calling the getMetadata() method.
1307:             *
1308:             * @param metadata the metadata
1309:             * @throws IllegalArgumentException if the properties are not consistent
1310:             */
1311:            //@ requires metadata != null;
1312:            private void setMetadata(ProtectedProperties metadata) {
1313:
1314:                m_Metadata = metadata;
1315:
1316:                if (m_Type == DATE) {
1317:                    m_Ordering = ORDERING_ORDERED;
1318:                    m_IsRegular = true;
1319:                    m_IsAveragable = false;
1320:                    m_HasZeropoint = false;
1321:                } else {
1322:
1323:                    // get ordering
1324:                    String orderString = m_Metadata.getProperty("ordering", "");
1325:
1326:                    // numeric ordered attributes are averagable and zeropoint by default
1327:                    String def;
1328:                    if (m_Type == NUMERIC
1329:                            && orderString.compareTo("modulo") != 0
1330:                            && orderString.compareTo("symbolic") != 0)
1331:                        def = "true";
1332:                    else
1333:                        def = "false";
1334:
1335:                    // determine boolean states
1336:                    m_IsAveragable = (m_Metadata
1337:                            .getProperty("averageable", def).compareTo("true") == 0);
1338:                    m_HasZeropoint = (m_Metadata.getProperty("zeropoint", def)
1339:                            .compareTo("true") == 0);
1340:                    // averagable or zeropoint implies regular
1341:                    if (m_IsAveragable || m_HasZeropoint)
1342:                        def = "true";
1343:                    m_IsRegular = (m_Metadata.getProperty("regular", def)
1344:                            .compareTo("true") == 0);
1345:
1346:                    // determine ordering
1347:                    if (orderString.compareTo("symbolic") == 0)
1348:                        m_Ordering = ORDERING_SYMBOLIC;
1349:                    else if (orderString.compareTo("ordered") == 0)
1350:                        m_Ordering = ORDERING_ORDERED;
1351:                    else if (orderString.compareTo("modulo") == 0)
1352:                        m_Ordering = ORDERING_MODULO;
1353:                    else {
1354:                        if (m_Type == NUMERIC || m_IsAveragable
1355:                                || m_HasZeropoint)
1356:                            m_Ordering = ORDERING_ORDERED;
1357:                        else
1358:                            m_Ordering = ORDERING_SYMBOLIC;
1359:                    }
1360:                }
1361:
1362:                // consistency checks
1363:                if (m_IsAveragable && !m_IsRegular)
1364:                    throw new IllegalArgumentException(
1365:                            "An averagable attribute must be" + " regular");
1366:                if (m_HasZeropoint && !m_IsRegular)
1367:                    throw new IllegalArgumentException(
1368:                            "A zeropoint attribute must be" + " regular");
1369:                if (m_IsRegular && m_Ordering == ORDERING_SYMBOLIC)
1370:                    throw new IllegalArgumentException(
1371:                            "A symbolic attribute cannot be" + " regular");
1372:                if (m_IsAveragable && m_Ordering != ORDERING_ORDERED)
1373:                    throw new IllegalArgumentException(
1374:                            "An averagable attribute must be" + " ordered");
1375:                if (m_HasZeropoint && m_Ordering != ORDERING_ORDERED)
1376:                    throw new IllegalArgumentException(
1377:                            "A zeropoint attribute must be" + " ordered");
1378:
1379:                // determine weight
1380:                m_Weight = 1.0;
1381:                String weightString = m_Metadata.getProperty("weight");
1382:                if (weightString != null) {
1383:                    try {
1384:                        m_Weight = Double.valueOf(weightString).doubleValue();
1385:                    } catch (NumberFormatException e) {
1386:                        // Check if value is really a number
1387:                        throw new IllegalArgumentException(
1388:                                "Not a valid attribute weight: '"
1389:                                        + weightString + "'");
1390:                    }
1391:                }
1392:
1393:                // determine numeric range
1394:                if (m_Type == NUMERIC)
1395:                    setNumericRange(m_Metadata.getProperty("range"));
1396:            }
1397:
1398:            /**
1399:             * Sets the numeric range based on a string. If the string is null the range
1400:             * will default to [-inf,+inf]. A square brace represents a closed interval, a
1401:             * curved brace represents an open interval, and 'inf' represents infinity.
1402:             * Examples of valid range strings: "[-inf,20)","(-13.5,-5.2)","(5,inf]"
1403:             *
1404:             * @param rangeString the string to parse as the attribute's numeric range
1405:             * @throws IllegalArgumentException if the range is not valid
1406:             */
1407:            //@ requires rangeString != null;
1408:            private void setNumericRange(String rangeString) {
1409:                // set defaults
1410:                m_LowerBound = Double.NEGATIVE_INFINITY;
1411:                m_LowerBoundIsOpen = false;
1412:                m_UpperBound = Double.POSITIVE_INFINITY;
1413:                m_UpperBoundIsOpen = false;
1414:
1415:                if (rangeString == null)
1416:                    return;
1417:
1418:                // set up a tokenzier to parse the string
1419:                StreamTokenizer tokenizer = new StreamTokenizer(
1420:                        new StringReader(rangeString));
1421:                tokenizer.resetSyntax();
1422:                tokenizer.whitespaceChars(0, ' ');
1423:                tokenizer.wordChars(' ' + 1, '\u00FF');
1424:                tokenizer.ordinaryChar('[');
1425:                tokenizer.ordinaryChar('(');
1426:                tokenizer.ordinaryChar(',');
1427:                tokenizer.ordinaryChar(']');
1428:                tokenizer.ordinaryChar(')');
1429:
1430:                try {
1431:
1432:                    // get opening brace
1433:                    tokenizer.nextToken();
1434:
1435:                    if (tokenizer.ttype == '[')
1436:                        m_LowerBoundIsOpen = false;
1437:                    else if (tokenizer.ttype == '(')
1438:                        m_LowerBoundIsOpen = true;
1439:                    else
1440:                        throw new IllegalArgumentException(
1441:                                "Expected opening brace on range," + " found: "
1442:                                        + tokenizer.toString());
1443:
1444:                    // get lower bound
1445:                    tokenizer.nextToken();
1446:                    if (tokenizer.ttype != tokenizer.TT_WORD)
1447:                        throw new IllegalArgumentException(
1448:                                "Expected lower bound in range," + " found: "
1449:                                        + tokenizer.toString());
1450:                    if (tokenizer.sval.compareToIgnoreCase("-inf") == 0)
1451:                        m_LowerBound = Double.NEGATIVE_INFINITY;
1452:                    else if (tokenizer.sval.compareToIgnoreCase("+inf") == 0)
1453:                        m_LowerBound = Double.POSITIVE_INFINITY;
1454:                    else if (tokenizer.sval.compareToIgnoreCase("inf") == 0)
1455:                        m_LowerBound = Double.NEGATIVE_INFINITY;
1456:                    else
1457:                        try {
1458:                            m_LowerBound = Double.valueOf(tokenizer.sval)
1459:                                    .doubleValue();
1460:                        } catch (NumberFormatException e) {
1461:                            throw new IllegalArgumentException(
1462:                                    "Expected lower bound in range,"
1463:                                            + " found: '" + tokenizer.sval
1464:                                            + "'");
1465:                        }
1466:
1467:                    // get separating comma
1468:                    if (tokenizer.nextToken() != ',')
1469:                        throw new IllegalArgumentException(
1470:                                "Expected comma in range," + " found: "
1471:                                        + tokenizer.toString());
1472:
1473:                    // get upper bound
1474:                    tokenizer.nextToken();
1475:                    if (tokenizer.ttype != tokenizer.TT_WORD)
1476:                        throw new IllegalArgumentException(
1477:                                "Expected upper bound in range," + " found: "
1478:                                        + tokenizer.toString());
1479:                    if (tokenizer.sval.compareToIgnoreCase("-inf") == 0)
1480:                        m_UpperBound = Double.NEGATIVE_INFINITY;
1481:                    else if (tokenizer.sval.compareToIgnoreCase("+inf") == 0)
1482:                        m_UpperBound = Double.POSITIVE_INFINITY;
1483:                    else if (tokenizer.sval.compareToIgnoreCase("inf") == 0)
1484:                        m_UpperBound = Double.POSITIVE_INFINITY;
1485:                    else
1486:                        try {
1487:                            m_UpperBound = Double.valueOf(tokenizer.sval)
1488:                                    .doubleValue();
1489:                        } catch (NumberFormatException e) {
1490:                            throw new IllegalArgumentException(
1491:                                    "Expected upper bound in range,"
1492:                                            + " found: '" + tokenizer.sval
1493:                                            + "'");
1494:                        }
1495:
1496:                    // get closing brace
1497:                    tokenizer.nextToken();
1498:
1499:                    if (tokenizer.ttype == ']')
1500:                        m_UpperBoundIsOpen = false;
1501:                    else if (tokenizer.ttype == ')')
1502:                        m_UpperBoundIsOpen = true;
1503:                    else
1504:                        throw new IllegalArgumentException(
1505:                                "Expected closing brace on range," + " found: "
1506:                                        + tokenizer.toString());
1507:
1508:                    // check for rubbish on end
1509:                    if (tokenizer.nextToken() != tokenizer.TT_EOF)
1510:                        throw new IllegalArgumentException(
1511:                                "Expected end of range string," + " found: "
1512:                                        + tokenizer.toString());
1513:
1514:                } catch (IOException e) {
1515:                    throw new IllegalArgumentException(
1516:                            "IOException reading attribute range" + " string: "
1517:                                    + e.getMessage());
1518:                }
1519:
1520:                if (m_UpperBound < m_LowerBound)
1521:                    throw new IllegalArgumentException("Upper bound ("
1522:                            + m_UpperBound + ") on numeric range is"
1523:                            + " less than lower bound (" + m_LowerBound + ")!");
1524:            }
1525:
1526:            /**
1527:             * Simple main method for testing this class.
1528:             * 
1529:             * @param ops the commandline options
1530:             */
1531:            //@ requires ops != null;
1532:            //@ requires \nonnullelements(ops);
1533:            public static void main(String[] ops) {
1534:
1535:                try {
1536:
1537:                    // Create numeric attributes "length" and "weight"
1538:                    Attribute length = new Attribute("length");
1539:                    Attribute weight = new Attribute("weight");
1540:
1541:                    // Create date attribute "date"
1542:                    Attribute date = new Attribute("date",
1543:                            "yyyy-MM-dd HH:mm:ss");
1544:
1545:                    System.out.println(date);
1546:                    double dd = date.parseDate("2001-04-04 14:13:55");
1547:                    System.out.println("Test date = " + dd);
1548:                    System.out.println(date.formatDate(dd));
1549:
1550:                    dd = new Date().getTime();
1551:                    System.out.println("Date now = " + dd);
1552:                    System.out.println(date.formatDate(dd));
1553:
1554:                    // Create vector to hold nominal values "first", "second", "third" 
1555:                    FastVector my_nominal_values = new FastVector(3);
1556:                    my_nominal_values.addElement("first");
1557:                    my_nominal_values.addElement("second");
1558:                    my_nominal_values.addElement("third");
1559:
1560:                    // Create nominal attribute "position" 
1561:                    Attribute position = new Attribute("position",
1562:                            my_nominal_values);
1563:
1564:                    // Print the name of "position"
1565:                    System.out.println("Name of \"position\": "
1566:                            + position.name());
1567:
1568:                    // Print the values of "position"
1569:                    Enumeration attValues = position.enumerateValues();
1570:                    while (attValues.hasMoreElements()) {
1571:                        String string = (String) attValues.nextElement();
1572:                        System.out.println("Value of \"position\": " + string);
1573:                    }
1574:
1575:                    // Shallow copy attribute "position"
1576:                    Attribute copy = (Attribute) position.copy();
1577:
1578:                    // Test if attributes are the same
1579:                    System.out.println("Copy is the same as original: "
1580:                            + copy.equals(position));
1581:
1582:                    // Print index of attribute "weight" (should be unset: -1)
1583:                    System.out
1584:                            .println("Index of attribute \"weight\" (should be -1): "
1585:                                    + weight.index());
1586:
1587:                    // Print index of value "first" of attribute "position"
1588:                    System.out
1589:                            .println("Index of value \"first\" of \"position\" (should be 0): "
1590:                                    + position.indexOfValue("first"));
1591:
1592:                    // Tests type of attribute "position"
1593:                    System.out.println("\"position\" is numeric: "
1594:                            + position.isNumeric());
1595:                    System.out.println("\"position\" is nominal: "
1596:                            + position.isNominal());
1597:                    System.out.println("\"position\" is string: "
1598:                            + position.isString());
1599:
1600:                    // Prints name of attribute "position"
1601:                    System.out.println("Name of \"position\": "
1602:                            + position.name());
1603:
1604:                    // Prints number of values of attribute "position"
1605:                    System.out.println("Number of values for \"position\": "
1606:                            + position.numValues());
1607:
1608:                    // Prints the values (againg)
1609:                    for (int i = 0; i < position.numValues(); i++) {
1610:                        System.out.println("Value " + i + ": "
1611:                                + position.value(i));
1612:                    }
1613:
1614:                    // Prints the attribute "position" in ARFF format
1615:                    System.out.println(position);
1616:
1617:                    // Checks type of attribute "position" using constants
1618:                    switch (position.type()) {
1619:                    case Attribute.NUMERIC:
1620:                        System.out.println("\"position\" is numeric");
1621:                        break;
1622:                    case Attribute.NOMINAL:
1623:                        System.out.println("\"position\" is nominal");
1624:                        break;
1625:                    case Attribute.STRING:
1626:                        System.out.println("\"position\" is string");
1627:                        break;
1628:                    case Attribute.DATE:
1629:                        System.out.println("\"position\" is date");
1630:                        break;
1631:                    case Attribute.RELATIONAL:
1632:                        System.out.println("\"position\" is relation-valued");
1633:                        break;
1634:                    default:
1635:                        System.out.println("\"position\" has unknown type");
1636:                    }
1637:
1638:                    FastVector atts = new FastVector(1);
1639:                    atts.addElement(position);
1640:                    Instances relation = new Instances("Test", atts, 0);
1641:                    Attribute relationValuedAtt = new Attribute("test",
1642:                            relation);
1643:                    System.out.println(relationValuedAtt);
1644:                } catch (Exception e) {
1645:                    e.printStackTrace();
1646:                }
1647:            }
1648:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.