1 | /* |
---|
2 | * This program is free software; you can redistribute it and/or modify |
---|
3 | * it under the terms of the GNU General Public License as published by |
---|
4 | * the Free Software Foundation; either version 2 of the License, or |
---|
5 | * (at your option) any later version. |
---|
6 | * |
---|
7 | * This program is distributed in the hope that it will be useful, |
---|
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
10 | * GNU General Public License for more details. |
---|
11 | * |
---|
12 | * You should have received a copy of the GNU General Public License |
---|
13 | * along with this program; if not, write to the Free Software |
---|
14 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
---|
15 | */ |
---|
16 | |
---|
17 | /* |
---|
18 | * Coordinates.java |
---|
19 | * Copyright (C) 2004 Stijn Lievens |
---|
20 | * |
---|
21 | */ |
---|
22 | |
---|
23 | package weka.classifiers.misc.monotone; |
---|
24 | |
---|
25 | import weka.core.Instance; |
---|
26 | import weka.core.RevisionHandler; |
---|
27 | import weka.core.RevisionUtils; |
---|
28 | |
---|
29 | import java.io.Serializable; |
---|
30 | |
---|
31 | /** |
---|
32 | * This is a simple implementation of the data space. The <code> |
---|
33 | * Coordinates </code> holds the internal weka value of an instance, |
---|
34 | * but <i> with the class removed </i>. The class is immutable, |
---|
35 | * and works best when all attibutes are nominal (ordinal), although |
---|
36 | * it will not give an error when working with numeric attributes. |
---|
37 | * In the latter case, performance will degrade because of the way |
---|
38 | * in which the hashcode is calculated. |
---|
39 | * |
---|
40 | * <p> |
---|
41 | * This implementation is part of the master's thesis: "Studie |
---|
42 | * en implementatie van instantie-gebaseerde algoritmen voor gesuperviseerd |
---|
43 | * rangschikken", Stijn Lievens, Ghent University, 2004. |
---|
44 | * </p> |
---|
45 | * |
---|
46 | * @author Stijn Lievens (stijn.lievens@ugent.be) |
---|
47 | * @version $Revision: 5922 $ |
---|
48 | */ |
---|
49 | public class Coordinates |
---|
50 | implements Serializable, RevisionHandler { |
---|
51 | |
---|
52 | /** for serialization */ |
---|
53 | private static final long serialVersionUID = 2319016195345994738L; |
---|
54 | |
---|
55 | /** |
---|
56 | * The internal weka values of the attributes of the instance, minus |
---|
57 | * the class attribute. |
---|
58 | */ |
---|
59 | private int[] m_coord; |
---|
60 | |
---|
61 | /** |
---|
62 | * The hashcode of this object. Calculated during construction. |
---|
63 | */ |
---|
64 | private int m_hashCode; |
---|
65 | |
---|
66 | /** |
---|
67 | * Create the <code> Coordinates </code> for the given instance. |
---|
68 | * |
---|
69 | * @param instance the <code> Instance </code> on which the <code> |
---|
70 | * Coordinates </code> will be based |
---|
71 | */ |
---|
72 | public Coordinates(Instance instance) { |
---|
73 | |
---|
74 | double[] values = instance.toDoubleArray(); |
---|
75 | int classIndex = instance.classIndex(); |
---|
76 | if (classIndex == -1) { |
---|
77 | m_coord = new int[values.length]; |
---|
78 | } else { |
---|
79 | m_coord = new int[values.length - 1]; |
---|
80 | } |
---|
81 | |
---|
82 | m_hashCode = 0; |
---|
83 | int factor=1; |
---|
84 | for (int i = 0,j = 0;i < values.length; i++) { |
---|
85 | if (i != classIndex) { |
---|
86 | m_coord[j] = (int) values[i]; |
---|
87 | if (i > 0 && i - 1 != classIndex) { |
---|
88 | factor *= instance.attribute(i-1).numValues(); |
---|
89 | } else if (i - 1 == classIndex && classIndex != -1 |
---|
90 | && classIndex != 0) { |
---|
91 | factor *= instance.attribute(i - 2).numValues(); |
---|
92 | } |
---|
93 | m_hashCode += (m_coord[j])*factor; |
---|
94 | j++; |
---|
95 | } |
---|
96 | } |
---|
97 | } |
---|
98 | |
---|
99 | /** |
---|
100 | * Get the value of the attribute with index <code> index, </code> |
---|
101 | * ignoring the class attribute. Indices are counted starting from |
---|
102 | * 0. |
---|
103 | * |
---|
104 | * @param index the index of the requested attribute |
---|
105 | * @return the value of this attribute, in internal floating point format. |
---|
106 | */ |
---|
107 | public double getValue(int index) { |
---|
108 | return m_coord[index]; |
---|
109 | } |
---|
110 | |
---|
111 | /** |
---|
112 | * Get the values of the coordinates. |
---|
113 | * |
---|
114 | * @param values array serving as output, and the first |
---|
115 | * <code> dimension() </code> values are filled in. |
---|
116 | */ |
---|
117 | public void getValues(double[] values) { |
---|
118 | // XXX this is a rather strange method, maybe it should be changed |
---|
119 | // into one that returns (using System.arraycopy) the requested values |
---|
120 | for (int i = 0; i < m_coord.length; i++) { |
---|
121 | values[i] = m_coord[i]; |
---|
122 | } |
---|
123 | } |
---|
124 | |
---|
125 | /** |
---|
126 | * Indicates if the object <code> o </code> equals <code> this. </code> |
---|
127 | * |
---|
128 | * @param o the reference object with which to compare |
---|
129 | * @return <code> true </code> if <code> o </code> equals <code> |
---|
130 | * this, </code> <code> false </code> otherwise |
---|
131 | */ |
---|
132 | public boolean equals(Object o) { |
---|
133 | if (! (o instanceof Coordinates) ) { |
---|
134 | return false; |
---|
135 | } |
---|
136 | |
---|
137 | Coordinates cc = (Coordinates) o; |
---|
138 | // if the length or hashCodes differ, the objects are certainly not equal |
---|
139 | if (m_coord.length != cc.m_coord.length || m_hashCode != cc.m_hashCode) { |
---|
140 | return false; |
---|
141 | } |
---|
142 | |
---|
143 | for (int i = 0; i < m_coord.length; i++) { |
---|
144 | if (m_coord[i] != cc.m_coord[i]) { |
---|
145 | return false; |
---|
146 | } |
---|
147 | } |
---|
148 | return true; |
---|
149 | } |
---|
150 | |
---|
151 | /** |
---|
152 | * Checks if <code> this </code> is strictly smaller than <code> cc. </code> |
---|
153 | * This means that for all indices i it holds that |
---|
154 | * <code> this.getValue(i) <= cc.getValue(i) </code> and that there is |
---|
155 | * at least one index i such that |
---|
156 | * <code> this.getValue(i) ≠ cc.getValue(i) </code> |
---|
157 | * |
---|
158 | * @param cc the <code> Coordinates </code> that <code> this </code> is |
---|
159 | * compared to |
---|
160 | * @return <code> true </code> if <code> this </code> is strictly |
---|
161 | * smaller than <code> cc, </code> <code> false </code> otherwise |
---|
162 | * @throws IllegalArgumentException if the dimensions of both objects differ |
---|
163 | */ |
---|
164 | public boolean strictlySmaller(Coordinates cc) throws IllegalArgumentException { |
---|
165 | if (cc.m_coord.length != m_coord.length) { |
---|
166 | throw new IllegalArgumentException |
---|
167 | ("Coordinates are not from the same space"); |
---|
168 | } |
---|
169 | |
---|
170 | // Skip all equal values |
---|
171 | int i = 0; |
---|
172 | while(i < m_coord.length && cc.m_coord[i] == m_coord[i]) { |
---|
173 | i++; |
---|
174 | } |
---|
175 | |
---|
176 | if (i == m_coord.length) { |
---|
177 | return false; // equality ! |
---|
178 | } |
---|
179 | |
---|
180 | for (; i < m_coord.length; i++) { |
---|
181 | if (m_coord[i] > cc.m_coord[i]) { |
---|
182 | return false; |
---|
183 | } |
---|
184 | } |
---|
185 | return true; |
---|
186 | } |
---|
187 | |
---|
188 | /** |
---|
189 | * Checks if <code> this </code> is smaller or equal than <code> cc. </code> |
---|
190 | * This means that for all indices i it holds that |
---|
191 | * <code> this.getValue(i) <= cc.getValue(i). </code> |
---|
192 | * |
---|
193 | * @param cc the <code> Coordinates </code> that <code> this </code> is |
---|
194 | * compared to |
---|
195 | * @return <code> true </code> if <code> this </code> is |
---|
196 | * smaller or equal than <code> cc, </code> <code> false </code> otherwise |
---|
197 | * @throws IllegalArgumentException if the dimensions of both objects differ |
---|
198 | */ |
---|
199 | public boolean smallerOrEqual(Coordinates cc) throws IllegalArgumentException { |
---|
200 | if (cc.m_coord.length != m_coord.length) { |
---|
201 | throw new IllegalArgumentException |
---|
202 | ("Coordinates are not from the same space"); |
---|
203 | } |
---|
204 | for (int i = 0; i < m_coord.length; i++) { |
---|
205 | if (m_coord[i] > cc.m_coord[i]) { |
---|
206 | return false; |
---|
207 | } |
---|
208 | } |
---|
209 | return true; |
---|
210 | } |
---|
211 | |
---|
212 | /** |
---|
213 | * Gets the hash code value for this object. |
---|
214 | * |
---|
215 | * @return the requested hash code |
---|
216 | */ |
---|
217 | public int hashCode() { |
---|
218 | return m_hashCode; |
---|
219 | } |
---|
220 | |
---|
221 | /** |
---|
222 | * Gets the dimension of the data space, this is the number of attributes, |
---|
223 | * exluding the class attribute. |
---|
224 | * |
---|
225 | * @return the dimension of the data space this object resides in |
---|
226 | */ |
---|
227 | public int dimension() { |
---|
228 | return m_coord.length; |
---|
229 | } |
---|
230 | |
---|
231 | /** |
---|
232 | * Get a string representation of this object. |
---|
233 | * |
---|
234 | * @return the requested string representation |
---|
235 | */ |
---|
236 | public String toString() { |
---|
237 | String s = "("; |
---|
238 | for (int i = 0; i < m_coord.length - 1; i++) { |
---|
239 | s += m_coord[i] + ","; |
---|
240 | } |
---|
241 | return s + m_coord[m_coord.length - 1] + ")"; |
---|
242 | } |
---|
243 | |
---|
244 | /** |
---|
245 | * Returns the revision string. |
---|
246 | * |
---|
247 | * @return the revision |
---|
248 | */ |
---|
249 | public String getRevision() { |
---|
250 | return RevisionUtils.extract("$Revision: 5922 $"); |
---|
251 | } |
---|
252 | } |
---|