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 | * Utils.java |
---|
19 | * Copyright (C) 1999-2004 University of Waikato, Hamilton, New Zealand |
---|
20 | * |
---|
21 | */ |
---|
22 | |
---|
23 | package weka.core; |
---|
24 | |
---|
25 | import java.lang.Math; |
---|
26 | import java.lang.reflect.Array; |
---|
27 | import java.util.Properties; |
---|
28 | import java.io.File; |
---|
29 | import java.io.FileInputStream; |
---|
30 | import java.util.Random; |
---|
31 | import java.util.Vector; |
---|
32 | |
---|
33 | /** |
---|
34 | * Class implementing some simple utility methods. |
---|
35 | * |
---|
36 | * @author Eibe Frank |
---|
37 | * @author Yong Wang |
---|
38 | * @author Len Trigg |
---|
39 | * @author Julien Prados |
---|
40 | * @version $Revision: 5987 $ |
---|
41 | */ |
---|
42 | public final class Utils |
---|
43 | implements RevisionHandler { |
---|
44 | |
---|
45 | /** The natural logarithm of 2. */ |
---|
46 | public static double log2 = Math.log(2); |
---|
47 | |
---|
48 | /** The small deviation allowed in double comparisons. */ |
---|
49 | public static double SMALL = 1e-6; |
---|
50 | |
---|
51 | /** |
---|
52 | * Tests if the given value codes "missing". |
---|
53 | * |
---|
54 | * @param val the value to be tested |
---|
55 | * @return true if val codes "missing" |
---|
56 | */ |
---|
57 | public static boolean isMissingValue(double val) { |
---|
58 | |
---|
59 | return Double.isNaN(val); |
---|
60 | } |
---|
61 | |
---|
62 | /** |
---|
63 | * Returns the value used to code a missing value. Note that |
---|
64 | * equality tests on this value will always return false, so use |
---|
65 | * isMissingValue(double val) for testing.. |
---|
66 | * |
---|
67 | * @return the value used as missing value. |
---|
68 | */ |
---|
69 | public static double missingValue() { |
---|
70 | |
---|
71 | return Double.NaN; |
---|
72 | } |
---|
73 | |
---|
74 | /** |
---|
75 | * Casting an object without "unchecked" compile-time warnings. |
---|
76 | * Use only when absolutely necessary (e.g. when using clone()). |
---|
77 | */ |
---|
78 | @SuppressWarnings("unchecked") |
---|
79 | public static <T> T cast(Object x) { |
---|
80 | return (T) x; |
---|
81 | } |
---|
82 | |
---|
83 | /** |
---|
84 | * Reads properties that inherit from three locations. Properties |
---|
85 | * are first defined in the system resource location (i.e. in the |
---|
86 | * CLASSPATH). These default properties must exist. Properties |
---|
87 | * defined in the users home directory (optional) override default |
---|
88 | * settings. Properties defined in the current directory (optional) |
---|
89 | * override all these settings. |
---|
90 | * |
---|
91 | * @param resourceName the location of the resource that should be |
---|
92 | * loaded. e.g.: "weka/core/Utils.props". (The use of hardcoded |
---|
93 | * forward slashes here is OK - see |
---|
94 | * jdk1.1/docs/guide/misc/resources.html) This routine will also |
---|
95 | * look for the file (in this case) "Utils.props" in the users home |
---|
96 | * directory and the current directory. |
---|
97 | * @return the Properties |
---|
98 | * @exception Exception if no default properties are defined, or if |
---|
99 | * an error occurs reading the properties files. |
---|
100 | */ |
---|
101 | public static Properties readProperties(String resourceName) |
---|
102 | throws Exception { |
---|
103 | |
---|
104 | Properties defaultProps = new Properties(); |
---|
105 | try { |
---|
106 | // Apparently hardcoded slashes are OK here |
---|
107 | // jdk1.1/docs/guide/misc/resources.html |
---|
108 | // defaultProps.load(ClassLoader.getSystemResourceAsStream(resourceName)); |
---|
109 | defaultProps.load((new Utils()).getClass().getClassLoader().getResourceAsStream(resourceName)); |
---|
110 | } catch (Exception ex) { |
---|
111 | /* throw new Exception("Problem reading default properties: " |
---|
112 | + ex.getMessage()); */ |
---|
113 | System.err.println("Warning, unable to load properties file from " |
---|
114 | +"system resource (Utils.java)"); |
---|
115 | } |
---|
116 | |
---|
117 | // Hardcoded slash is OK here |
---|
118 | // eg: see jdk1.1/docs/guide/misc/resources.html |
---|
119 | int slInd = resourceName.lastIndexOf('/'); |
---|
120 | if (slInd != -1) { |
---|
121 | resourceName = resourceName.substring(slInd + 1); |
---|
122 | } |
---|
123 | |
---|
124 | // Allow a properties file in the home directory to override |
---|
125 | Properties userProps = new Properties(defaultProps); |
---|
126 | File propFile = new File(System.getProperties().getProperty("user.home") |
---|
127 | + File.separatorChar |
---|
128 | + resourceName); |
---|
129 | if (propFile.exists()) { |
---|
130 | try { |
---|
131 | userProps.load(new FileInputStream(propFile)); |
---|
132 | } catch (Exception ex) { |
---|
133 | throw new Exception("Problem reading user properties: " + propFile); |
---|
134 | } |
---|
135 | } |
---|
136 | |
---|
137 | // Allow a properties file in the current directory to override |
---|
138 | Properties localProps = new Properties(userProps); |
---|
139 | propFile = new File(resourceName); |
---|
140 | if (propFile.exists()) { |
---|
141 | try { |
---|
142 | localProps.load(new FileInputStream(propFile)); |
---|
143 | } catch (Exception ex) { |
---|
144 | throw new Exception("Problem reading local properties: " + propFile); |
---|
145 | } |
---|
146 | } |
---|
147 | |
---|
148 | return localProps; |
---|
149 | } |
---|
150 | |
---|
151 | /** |
---|
152 | * Returns the correlation coefficient of two double vectors. |
---|
153 | * |
---|
154 | * @param y1 double vector 1 |
---|
155 | * @param y2 double vector 2 |
---|
156 | * @param n the length of two double vectors |
---|
157 | * @return the correlation coefficient |
---|
158 | */ |
---|
159 | public static final double correlation(double y1[],double y2[],int n) { |
---|
160 | |
---|
161 | int i; |
---|
162 | double av1 = 0.0, av2 = 0.0, y11 = 0.0, y22 = 0.0, y12 = 0.0, c; |
---|
163 | |
---|
164 | if (n <= 1) { |
---|
165 | return 1.0; |
---|
166 | } |
---|
167 | for (i = 0; i < n; i++) { |
---|
168 | av1 += y1[i]; |
---|
169 | av2 += y2[i]; |
---|
170 | } |
---|
171 | av1 /= (double) n; |
---|
172 | av2 /= (double) n; |
---|
173 | for (i = 0; i < n; i++) { |
---|
174 | y11 += (y1[i] - av1) * (y1[i] - av1); |
---|
175 | y22 += (y2[i] - av2) * (y2[i] - av2); |
---|
176 | y12 += (y1[i] - av1) * (y2[i] - av2); |
---|
177 | } |
---|
178 | if (y11 * y22 == 0.0) { |
---|
179 | c=1.0; |
---|
180 | } else { |
---|
181 | c = y12 / Math.sqrt(Math.abs(y11 * y22)); |
---|
182 | } |
---|
183 | |
---|
184 | return c; |
---|
185 | } |
---|
186 | |
---|
187 | /** |
---|
188 | * Removes all occurrences of a string from another string. |
---|
189 | * |
---|
190 | * @param inString the string to remove substrings from. |
---|
191 | * @param substring the substring to remove. |
---|
192 | * @return the input string with occurrences of substring removed. |
---|
193 | */ |
---|
194 | public static String removeSubstring(String inString, String substring) { |
---|
195 | |
---|
196 | StringBuffer result = new StringBuffer(); |
---|
197 | int oldLoc = 0, loc = 0; |
---|
198 | while ((loc = inString.indexOf(substring, oldLoc))!= -1) { |
---|
199 | result.append(inString.substring(oldLoc, loc)); |
---|
200 | oldLoc = loc + substring.length(); |
---|
201 | } |
---|
202 | result.append(inString.substring(oldLoc)); |
---|
203 | return result.toString(); |
---|
204 | } |
---|
205 | |
---|
206 | /** |
---|
207 | * Replaces with a new string, all occurrences of a string from |
---|
208 | * another string. |
---|
209 | * |
---|
210 | * @param inString the string to replace substrings in. |
---|
211 | * @param subString the substring to replace. |
---|
212 | * @param replaceString the replacement substring |
---|
213 | * @return the input string with occurrences of substring replaced. |
---|
214 | */ |
---|
215 | public static String replaceSubstring(String inString, String subString, |
---|
216 | String replaceString) { |
---|
217 | |
---|
218 | StringBuffer result = new StringBuffer(); |
---|
219 | int oldLoc = 0, loc = 0; |
---|
220 | while ((loc = inString.indexOf(subString, oldLoc))!= -1) { |
---|
221 | result.append(inString.substring(oldLoc, loc)); |
---|
222 | result.append(replaceString); |
---|
223 | oldLoc = loc + subString.length(); |
---|
224 | } |
---|
225 | result.append(inString.substring(oldLoc)); |
---|
226 | return result.toString(); |
---|
227 | } |
---|
228 | |
---|
229 | |
---|
230 | /** |
---|
231 | * Pads a string to a specified length, inserting spaces on the left |
---|
232 | * as required. If the string is too long, characters are removed (from |
---|
233 | * the right). |
---|
234 | * |
---|
235 | * @param inString the input string |
---|
236 | * @param length the desired length of the output string |
---|
237 | * @return the output string |
---|
238 | */ |
---|
239 | public static String padLeft(String inString, int length) { |
---|
240 | |
---|
241 | return fixStringLength(inString, length, false); |
---|
242 | } |
---|
243 | |
---|
244 | /** |
---|
245 | * Pads a string to a specified length, inserting spaces on the right |
---|
246 | * as required. If the string is too long, characters are removed (from |
---|
247 | * the right). |
---|
248 | * |
---|
249 | * @param inString the input string |
---|
250 | * @param length the desired length of the output string |
---|
251 | * @return the output string |
---|
252 | */ |
---|
253 | public static String padRight(String inString, int length) { |
---|
254 | |
---|
255 | return fixStringLength(inString, length, true); |
---|
256 | } |
---|
257 | |
---|
258 | /** |
---|
259 | * Pads a string to a specified length, inserting spaces as |
---|
260 | * required. If the string is too long, characters are removed (from |
---|
261 | * the right). |
---|
262 | * |
---|
263 | * @param inString the input string |
---|
264 | * @param length the desired length of the output string |
---|
265 | * @param right true if inserted spaces should be added to the right |
---|
266 | * @return the output string |
---|
267 | */ |
---|
268 | private static /*@pure@*/ String fixStringLength(String inString, int length, |
---|
269 | boolean right) { |
---|
270 | |
---|
271 | if (inString.length() < length) { |
---|
272 | while (inString.length() < length) { |
---|
273 | inString = (right ? inString.concat(" ") : " ".concat(inString)); |
---|
274 | } |
---|
275 | } else if (inString.length() > length) { |
---|
276 | inString = inString.substring(0, length); |
---|
277 | } |
---|
278 | return inString; |
---|
279 | } |
---|
280 | |
---|
281 | /** |
---|
282 | * Rounds a double and converts it into String. |
---|
283 | * |
---|
284 | * @param value the double value |
---|
285 | * @param afterDecimalPoint the (maximum) number of digits permitted |
---|
286 | * after the decimal point |
---|
287 | * @return the double as a formatted string |
---|
288 | */ |
---|
289 | public static /*@pure@*/ String doubleToString(double value, int afterDecimalPoint) { |
---|
290 | |
---|
291 | StringBuffer stringBuffer; |
---|
292 | double temp; |
---|
293 | int dotPosition; |
---|
294 | long precisionValue; |
---|
295 | |
---|
296 | temp = value * Math.pow(10.0, afterDecimalPoint); |
---|
297 | if (Math.abs(temp) < Long.MAX_VALUE) { |
---|
298 | precisionValue = (temp > 0) ? (long)(temp + 0.5) |
---|
299 | : -(long)(Math.abs(temp) + 0.5); |
---|
300 | if (precisionValue == 0) { |
---|
301 | stringBuffer = new StringBuffer(String.valueOf(0)); |
---|
302 | } else { |
---|
303 | stringBuffer = new StringBuffer(String.valueOf(precisionValue)); |
---|
304 | } |
---|
305 | if (afterDecimalPoint == 0) { |
---|
306 | return stringBuffer.toString(); |
---|
307 | } |
---|
308 | dotPosition = stringBuffer.length() - afterDecimalPoint; |
---|
309 | while (((precisionValue < 0) && (dotPosition < 1)) || |
---|
310 | (dotPosition < 0)) { |
---|
311 | if (precisionValue < 0) { |
---|
312 | stringBuffer.insert(1, '0'); |
---|
313 | } else { |
---|
314 | stringBuffer.insert(0, '0'); |
---|
315 | } |
---|
316 | dotPosition++; |
---|
317 | } |
---|
318 | stringBuffer.insert(dotPosition, '.'); |
---|
319 | if ((precisionValue < 0) && (stringBuffer.charAt(1) == '.')) { |
---|
320 | stringBuffer.insert(1, '0'); |
---|
321 | } else if (stringBuffer.charAt(0) == '.') { |
---|
322 | stringBuffer.insert(0, '0'); |
---|
323 | } |
---|
324 | int currentPos = stringBuffer.length() - 1; |
---|
325 | while ((currentPos > dotPosition) && |
---|
326 | (stringBuffer.charAt(currentPos) == '0')) { |
---|
327 | stringBuffer.setCharAt(currentPos--, ' '); |
---|
328 | } |
---|
329 | if (stringBuffer.charAt(currentPos) == '.') { |
---|
330 | stringBuffer.setCharAt(currentPos, ' '); |
---|
331 | } |
---|
332 | |
---|
333 | return stringBuffer.toString().trim(); |
---|
334 | } |
---|
335 | return new String("" + value); |
---|
336 | } |
---|
337 | |
---|
338 | /** |
---|
339 | * Rounds a double and converts it into a formatted decimal-justified String. |
---|
340 | * Trailing 0's are replaced with spaces. |
---|
341 | * |
---|
342 | * @param value the double value |
---|
343 | * @param width the width of the string |
---|
344 | * @param afterDecimalPoint the number of digits after the decimal point |
---|
345 | * @return the double as a formatted string |
---|
346 | */ |
---|
347 | public static /*@pure@*/ String doubleToString(double value, int width, |
---|
348 | int afterDecimalPoint) { |
---|
349 | |
---|
350 | String tempString = doubleToString(value, afterDecimalPoint); |
---|
351 | char[] result; |
---|
352 | int dotPosition; |
---|
353 | |
---|
354 | if ((afterDecimalPoint >= width) |
---|
355 | || (tempString.indexOf('E') != -1)) { // Protects sci notation |
---|
356 | return tempString; |
---|
357 | } |
---|
358 | |
---|
359 | // Initialize result |
---|
360 | result = new char[width]; |
---|
361 | for (int i = 0; i < result.length; i++) { |
---|
362 | result[i] = ' '; |
---|
363 | } |
---|
364 | |
---|
365 | if (afterDecimalPoint > 0) { |
---|
366 | // Get position of decimal point and insert decimal point |
---|
367 | dotPosition = tempString.indexOf('.'); |
---|
368 | if (dotPosition == -1) { |
---|
369 | dotPosition = tempString.length(); |
---|
370 | } else { |
---|
371 | result[width - afterDecimalPoint - 1] = '.'; |
---|
372 | } |
---|
373 | } else { |
---|
374 | dotPosition = tempString.length(); |
---|
375 | } |
---|
376 | |
---|
377 | |
---|
378 | int offset = width - afterDecimalPoint - dotPosition; |
---|
379 | if (afterDecimalPoint > 0) { |
---|
380 | offset--; |
---|
381 | } |
---|
382 | |
---|
383 | // Not enough room to decimal align within the supplied width |
---|
384 | if (offset < 0) { |
---|
385 | return tempString; |
---|
386 | } |
---|
387 | |
---|
388 | // Copy characters before decimal point |
---|
389 | for (int i = 0; i < dotPosition; i++) { |
---|
390 | result[offset + i] = tempString.charAt(i); |
---|
391 | } |
---|
392 | |
---|
393 | // Copy characters after decimal point |
---|
394 | for (int i = dotPosition + 1; i < tempString.length(); i++) { |
---|
395 | result[offset + i] = tempString.charAt(i); |
---|
396 | } |
---|
397 | |
---|
398 | return new String(result); |
---|
399 | } |
---|
400 | |
---|
401 | /** |
---|
402 | * Returns the basic class of an array class (handles multi-dimensional |
---|
403 | * arrays). |
---|
404 | * @param c the array to inspect |
---|
405 | * @return the class of the innermost elements |
---|
406 | */ |
---|
407 | public static Class getArrayClass(Class c) { |
---|
408 | if (c.getComponentType().isArray()) |
---|
409 | return getArrayClass(c.getComponentType()); |
---|
410 | else |
---|
411 | return c.getComponentType(); |
---|
412 | } |
---|
413 | |
---|
414 | /** |
---|
415 | * Returns the dimensions of the given array. Even though the |
---|
416 | * parameter is of type "Object" one can hand over primitve arrays, e.g. |
---|
417 | * int[3] or double[2][4]. |
---|
418 | * |
---|
419 | * @param array the array to determine the dimensions for |
---|
420 | * @return the dimensions of the array |
---|
421 | */ |
---|
422 | public static int getArrayDimensions(Class array) { |
---|
423 | if (array.getComponentType().isArray()) |
---|
424 | return 1 + getArrayDimensions(array.getComponentType()); |
---|
425 | else |
---|
426 | return 1; |
---|
427 | } |
---|
428 | |
---|
429 | /** |
---|
430 | * Returns the dimensions of the given array. Even though the |
---|
431 | * parameter is of type "Object" one can hand over primitve arrays, e.g. |
---|
432 | * int[3] or double[2][4]. |
---|
433 | * |
---|
434 | * @param array the array to determine the dimensions for |
---|
435 | * @return the dimensions of the array |
---|
436 | */ |
---|
437 | public static int getArrayDimensions(Object array) { |
---|
438 | return getArrayDimensions(array.getClass()); |
---|
439 | } |
---|
440 | |
---|
441 | /** |
---|
442 | * Returns the given Array in a string representation. Even though the |
---|
443 | * parameter is of type "Object" one can hand over primitve arrays, e.g. |
---|
444 | * int[3] or double[2][4]. |
---|
445 | * |
---|
446 | * @param array the array to return in a string representation |
---|
447 | * @return the array as string |
---|
448 | */ |
---|
449 | public static String arrayToString(Object array) { |
---|
450 | String result; |
---|
451 | int dimensions; |
---|
452 | int i; |
---|
453 | |
---|
454 | result = ""; |
---|
455 | dimensions = getArrayDimensions(array); |
---|
456 | |
---|
457 | if (dimensions == 0) { |
---|
458 | result = "null"; |
---|
459 | } |
---|
460 | else if (dimensions == 1) { |
---|
461 | for (i = 0; i < Array.getLength(array); i++) { |
---|
462 | if (i > 0) |
---|
463 | result += ","; |
---|
464 | if (Array.get(array, i) == null) |
---|
465 | result += "null"; |
---|
466 | else |
---|
467 | result += Array.get(array, i).toString(); |
---|
468 | } |
---|
469 | } |
---|
470 | else { |
---|
471 | for (i = 0; i < Array.getLength(array); i++) { |
---|
472 | if (i > 0) |
---|
473 | result += ","; |
---|
474 | result += "[" + arrayToString(Array.get(array, i)) + "]"; |
---|
475 | } |
---|
476 | } |
---|
477 | |
---|
478 | return result; |
---|
479 | } |
---|
480 | |
---|
481 | /** |
---|
482 | * Tests if a is equal to b. |
---|
483 | * |
---|
484 | * @param a a double |
---|
485 | * @param b a double |
---|
486 | */ |
---|
487 | public static /*@pure@*/ boolean eq(double a, double b){ |
---|
488 | |
---|
489 | return (a - b < SMALL) && (b - a < SMALL); |
---|
490 | } |
---|
491 | |
---|
492 | /** |
---|
493 | * Checks if the given array contains any non-empty options. |
---|
494 | * |
---|
495 | * @param options an array of strings |
---|
496 | * @exception Exception if there are any non-empty options |
---|
497 | */ |
---|
498 | public static void checkForRemainingOptions(String[] options) |
---|
499 | throws Exception { |
---|
500 | |
---|
501 | int illegalOptionsFound = 0; |
---|
502 | StringBuffer text = new StringBuffer(); |
---|
503 | |
---|
504 | if (options == null) { |
---|
505 | return; |
---|
506 | } |
---|
507 | for (int i = 0; i < options.length; i++) { |
---|
508 | if (options[i].length() > 0) { |
---|
509 | illegalOptionsFound++; |
---|
510 | text.append(options[i] + ' '); |
---|
511 | } |
---|
512 | } |
---|
513 | if (illegalOptionsFound > 0) { |
---|
514 | throw new Exception("Illegal options: " + text); |
---|
515 | } |
---|
516 | } |
---|
517 | |
---|
518 | /** |
---|
519 | * Checks if the given array contains the flag "-Char". Stops |
---|
520 | * searching at the first marker "--". If the flag is found, |
---|
521 | * it is replaced with the empty string. |
---|
522 | * |
---|
523 | * @param flag the character indicating the flag. |
---|
524 | * @param options the array of strings containing all the options. |
---|
525 | * @return true if the flag was found |
---|
526 | * @exception Exception if an illegal option was found |
---|
527 | */ |
---|
528 | public static boolean getFlag(char flag, String[] options) |
---|
529 | throws Exception { |
---|
530 | |
---|
531 | return getFlag("" + flag, options); |
---|
532 | } |
---|
533 | |
---|
534 | /** |
---|
535 | * Checks if the given array contains the flag "-String". Stops |
---|
536 | * searching at the first marker "--". If the flag is found, |
---|
537 | * it is replaced with the empty string. |
---|
538 | * |
---|
539 | * @param flag the String indicating the flag. |
---|
540 | * @param options the array of strings containing all the options. |
---|
541 | * @return true if the flag was found |
---|
542 | * @exception Exception if an illegal option was found |
---|
543 | */ |
---|
544 | public static boolean getFlag(String flag, String[] options) |
---|
545 | throws Exception { |
---|
546 | |
---|
547 | int pos = getOptionPos(flag, options); |
---|
548 | |
---|
549 | if (pos > -1) |
---|
550 | options[pos] = ""; |
---|
551 | |
---|
552 | return (pos > -1); |
---|
553 | } |
---|
554 | |
---|
555 | /** |
---|
556 | * Gets an option indicated by a flag "-Char" from the given array |
---|
557 | * of strings. Stops searching at the first marker "--". Replaces |
---|
558 | * flag and option with empty strings. |
---|
559 | * |
---|
560 | * @param flag the character indicating the option. |
---|
561 | * @param options the array of strings containing all the options. |
---|
562 | * @return the indicated option or an empty string |
---|
563 | * @exception Exception if the option indicated by the flag can't be found |
---|
564 | */ |
---|
565 | public static /*@non_null@*/ String getOption(char flag, String[] options) |
---|
566 | throws Exception { |
---|
567 | |
---|
568 | return getOption("" + flag, options); |
---|
569 | } |
---|
570 | |
---|
571 | /** |
---|
572 | * Gets an option indicated by a flag "-String" from the given array |
---|
573 | * of strings. Stops searching at the first marker "--". Replaces |
---|
574 | * flag and option with empty strings. |
---|
575 | * |
---|
576 | * @param flag the String indicating the option. |
---|
577 | * @param options the array of strings containing all the options. |
---|
578 | * @return the indicated option or an empty string |
---|
579 | * @exception Exception if the option indicated by the flag can't be found |
---|
580 | */ |
---|
581 | public static /*@non_null@*/ String getOption(String flag, String[] options) |
---|
582 | throws Exception { |
---|
583 | |
---|
584 | String newString; |
---|
585 | int i = getOptionPos(flag, options); |
---|
586 | |
---|
587 | if (i > -1) { |
---|
588 | if (options[i].equals("-" + flag)) { |
---|
589 | if (i + 1 == options.length) { |
---|
590 | throw new Exception("No value given for -" + flag + " option."); |
---|
591 | } |
---|
592 | options[i] = ""; |
---|
593 | newString = new String(options[i + 1]); |
---|
594 | options[i + 1] = ""; |
---|
595 | return newString; |
---|
596 | } |
---|
597 | if (options[i].charAt(1) == '-') { |
---|
598 | return ""; |
---|
599 | } |
---|
600 | } |
---|
601 | |
---|
602 | return ""; |
---|
603 | } |
---|
604 | |
---|
605 | /** |
---|
606 | * Gets the index of an option or flag indicated by a flag "-Char" from |
---|
607 | * the given array of strings. Stops searching at the first marker "--". |
---|
608 | * |
---|
609 | * @param flag the character indicating the option. |
---|
610 | * @param options the array of strings containing all the options. |
---|
611 | * @return the position if found, or -1 otherwise |
---|
612 | */ |
---|
613 | public static int getOptionPos(char flag, String[] options) { |
---|
614 | return getOptionPos("" + flag, options); |
---|
615 | } |
---|
616 | |
---|
617 | /** |
---|
618 | * Gets the index of an option or flag indicated by a flag "-String" from |
---|
619 | * the given array of strings. Stops searching at the first marker "--". |
---|
620 | * |
---|
621 | * @param flag the String indicating the option. |
---|
622 | * @param options the array of strings containing all the options. |
---|
623 | * @return the position if found, or -1 otherwise |
---|
624 | */ |
---|
625 | public static int getOptionPos(String flag, String[] options) { |
---|
626 | if (options == null) |
---|
627 | return -1; |
---|
628 | |
---|
629 | for (int i = 0; i < options.length; i++) { |
---|
630 | if ((options[i].length() > 0) && (options[i].charAt(0) == '-')) { |
---|
631 | // Check if it is a negative number |
---|
632 | try { |
---|
633 | Double.valueOf(options[i]); |
---|
634 | } |
---|
635 | catch (NumberFormatException e) { |
---|
636 | // found? |
---|
637 | if (options[i].equals("-" + flag)) |
---|
638 | return i; |
---|
639 | // did we reach "--"? |
---|
640 | if (options[i].charAt(1) == '-') |
---|
641 | return -1; |
---|
642 | } |
---|
643 | } |
---|
644 | } |
---|
645 | |
---|
646 | return -1; |
---|
647 | } |
---|
648 | |
---|
649 | /** |
---|
650 | * Quotes a string if it contains special characters. |
---|
651 | * |
---|
652 | * The following rules are applied: |
---|
653 | * |
---|
654 | * A character is backquoted version of it is one |
---|
655 | * of <tt>" ' % \ \n \r \t</tt>. |
---|
656 | * |
---|
657 | * A string is enclosed within single quotes if a character has been |
---|
658 | * backquoted using the previous rule above or contains |
---|
659 | * <tt>{ }</tt> or is exactly equal to the strings |
---|
660 | * <tt>, ? space or ""</tt> (empty string). |
---|
661 | * |
---|
662 | * A quoted question mark distinguishes it from the missing value which |
---|
663 | * is represented as an unquoted question mark in arff files. |
---|
664 | * |
---|
665 | * @param string the string to be quoted |
---|
666 | * @return the string (possibly quoted) |
---|
667 | * @see #unquote(String) |
---|
668 | */ |
---|
669 | public static /*@pure@*/ String quote(String string) { |
---|
670 | boolean quote = false; |
---|
671 | |
---|
672 | // backquote the following characters |
---|
673 | if ((string.indexOf('\n') != -1) || (string.indexOf('\r') != -1) || |
---|
674 | (string.indexOf('\'') != -1) || (string.indexOf('"') != -1) || |
---|
675 | (string.indexOf('\\') != -1) || |
---|
676 | (string.indexOf('\t') != -1) || (string.indexOf('%') != -1)) { |
---|
677 | string = backQuoteChars(string); |
---|
678 | quote = true; |
---|
679 | } |
---|
680 | |
---|
681 | // Enclose the string in 's if the string contains a recently added |
---|
682 | // backquote or contains one of the following characters. |
---|
683 | if((quote == true) || |
---|
684 | (string.indexOf('{') != -1) || (string.indexOf('}') != -1) || |
---|
685 | (string.indexOf(',') != -1) || (string.equals("?")) || |
---|
686 | (string.indexOf(' ') != -1) || (string.equals(""))) { |
---|
687 | string = ("'".concat(string)).concat("'"); |
---|
688 | } |
---|
689 | |
---|
690 | return string; |
---|
691 | } |
---|
692 | |
---|
693 | /** |
---|
694 | * unquotes are previously quoted string (but only if necessary), i.e., it |
---|
695 | * removes the single quotes around it. Inverse to quote(String). |
---|
696 | * |
---|
697 | * @param string the string to process |
---|
698 | * @return the unquoted string |
---|
699 | * @see #quote(String) |
---|
700 | */ |
---|
701 | public static String unquote(String string) { |
---|
702 | if (string.startsWith("'") && string.endsWith("'")) { |
---|
703 | string = string.substring(1, string.length() - 1); |
---|
704 | |
---|
705 | if ((string.indexOf("\\n") != -1) || (string.indexOf("\\r") != -1) || |
---|
706 | (string.indexOf("\\'") != -1) || (string.indexOf("\\\"") != -1) || |
---|
707 | (string.indexOf("\\\\") != -1) || |
---|
708 | (string.indexOf("\\t") != -1) || (string.indexOf("\\%") != -1)) { |
---|
709 | string = unbackQuoteChars(string); |
---|
710 | } |
---|
711 | } |
---|
712 | |
---|
713 | return string; |
---|
714 | } |
---|
715 | |
---|
716 | /** |
---|
717 | * Converts carriage returns and new lines in a string into \r and \n. |
---|
718 | * Backquotes the following characters: ` " \ \t and % |
---|
719 | * |
---|
720 | * @param string the string |
---|
721 | * @return the converted string |
---|
722 | * @see #unbackQuoteChars(String) |
---|
723 | */ |
---|
724 | public static /*@pure@*/ String backQuoteChars(String string) { |
---|
725 | |
---|
726 | int index; |
---|
727 | StringBuffer newStringBuffer; |
---|
728 | |
---|
729 | // replace each of the following characters with the backquoted version |
---|
730 | char charsFind[] = {'\\', '\'', '\t', '\n', '\r', '"', '%'}; |
---|
731 | String charsReplace[] = {"\\\\", "\\'", "\\t", "\\n", "\\r", "\\\"", "\\%"}; |
---|
732 | for (int i = 0; i < charsFind.length; i++) { |
---|
733 | if (string.indexOf(charsFind[i]) != -1 ) { |
---|
734 | newStringBuffer = new StringBuffer(); |
---|
735 | while ((index = string.indexOf(charsFind[i])) != -1) { |
---|
736 | if (index > 0) { |
---|
737 | newStringBuffer.append(string.substring(0, index)); |
---|
738 | } |
---|
739 | newStringBuffer.append(charsReplace[i]); |
---|
740 | if ((index + 1) < string.length()) { |
---|
741 | string = string.substring(index + 1); |
---|
742 | } else { |
---|
743 | string = ""; |
---|
744 | } |
---|
745 | } |
---|
746 | newStringBuffer.append(string); |
---|
747 | string = newStringBuffer.toString(); |
---|
748 | } |
---|
749 | } |
---|
750 | |
---|
751 | return string; |
---|
752 | } |
---|
753 | |
---|
754 | /** |
---|
755 | * Converts carriage returns and new lines in a string into \r and \n. |
---|
756 | * |
---|
757 | * @param string the string |
---|
758 | * @return the converted string |
---|
759 | */ |
---|
760 | public static String convertNewLines(String string) { |
---|
761 | int index; |
---|
762 | |
---|
763 | // Replace with \n |
---|
764 | StringBuffer newStringBuffer = new StringBuffer(); |
---|
765 | while ((index = string.indexOf('\n')) != -1) { |
---|
766 | if (index > 0) { |
---|
767 | newStringBuffer.append(string.substring(0, index)); |
---|
768 | } |
---|
769 | newStringBuffer.append('\\'); |
---|
770 | newStringBuffer.append('n'); |
---|
771 | if ((index + 1) < string.length()) { |
---|
772 | string = string.substring(index + 1); |
---|
773 | } else { |
---|
774 | string = ""; |
---|
775 | } |
---|
776 | } |
---|
777 | newStringBuffer.append(string); |
---|
778 | string = newStringBuffer.toString(); |
---|
779 | |
---|
780 | // Replace with \r |
---|
781 | newStringBuffer = new StringBuffer(); |
---|
782 | while ((index = string.indexOf('\r')) != -1) { |
---|
783 | if (index > 0) { |
---|
784 | newStringBuffer.append(string.substring(0, index)); |
---|
785 | } |
---|
786 | newStringBuffer.append('\\'); |
---|
787 | newStringBuffer.append('r'); |
---|
788 | if ((index + 1) < string.length()){ |
---|
789 | string = string.substring(index + 1); |
---|
790 | } else { |
---|
791 | string = ""; |
---|
792 | } |
---|
793 | } |
---|
794 | newStringBuffer.append(string); |
---|
795 | return newStringBuffer.toString(); |
---|
796 | } |
---|
797 | |
---|
798 | /** |
---|
799 | * Reverts \r and \n in a string into carriage returns and new lines. |
---|
800 | * |
---|
801 | * @param string the string |
---|
802 | * @return the converted string |
---|
803 | */ |
---|
804 | public static String revertNewLines(String string) { |
---|
805 | int index; |
---|
806 | |
---|
807 | // Replace with \n |
---|
808 | StringBuffer newStringBuffer = new StringBuffer(); |
---|
809 | while ((index = string.indexOf("\\n")) != -1) { |
---|
810 | if (index > 0) { |
---|
811 | newStringBuffer.append(string.substring(0, index)); |
---|
812 | } |
---|
813 | newStringBuffer.append('\n'); |
---|
814 | if ((index + 2) < string.length()) { |
---|
815 | string = string.substring(index + 2); |
---|
816 | } else { |
---|
817 | string = ""; |
---|
818 | } |
---|
819 | } |
---|
820 | newStringBuffer.append(string); |
---|
821 | string = newStringBuffer.toString(); |
---|
822 | |
---|
823 | // Replace with \r |
---|
824 | newStringBuffer = new StringBuffer(); |
---|
825 | while ((index = string.indexOf("\\r")) != -1) { |
---|
826 | if (index > 0) { |
---|
827 | newStringBuffer.append(string.substring(0, index)); |
---|
828 | } |
---|
829 | newStringBuffer.append('\r'); |
---|
830 | if ((index + 2) < string.length()){ |
---|
831 | string = string.substring(index + 2); |
---|
832 | } else { |
---|
833 | string = ""; |
---|
834 | } |
---|
835 | } |
---|
836 | newStringBuffer.append(string); |
---|
837 | |
---|
838 | return newStringBuffer.toString(); |
---|
839 | } |
---|
840 | |
---|
841 | /** |
---|
842 | * Returns the secondary set of options (if any) contained in |
---|
843 | * the supplied options array. The secondary set is defined to |
---|
844 | * be any options after the first "--". These options are removed from |
---|
845 | * the original options array. |
---|
846 | * |
---|
847 | * @param options the input array of options |
---|
848 | * @return the array of secondary options |
---|
849 | */ |
---|
850 | public static String[] partitionOptions(String[] options) { |
---|
851 | |
---|
852 | for (int i = 0; i < options.length; i++) { |
---|
853 | if (options[i].equals("--")) { |
---|
854 | options[i++] = ""; |
---|
855 | String[] result = new String [options.length - i]; |
---|
856 | for (int j = i; j < options.length; j++) { |
---|
857 | result[j - i] = options[j]; |
---|
858 | options[j] = ""; |
---|
859 | } |
---|
860 | return result; |
---|
861 | } |
---|
862 | } |
---|
863 | return new String [0]; |
---|
864 | } |
---|
865 | |
---|
866 | /** |
---|
867 | * The inverse operation of backQuoteChars(). |
---|
868 | * Converts back-quoted carriage returns and new lines in a string |
---|
869 | * to the corresponding character ('\r' and '\n'). |
---|
870 | * Also "un"-back-quotes the following characters: ` " \ \t and % |
---|
871 | * |
---|
872 | * @param string the string |
---|
873 | * @return the converted string |
---|
874 | * @see #backQuoteChars(String) |
---|
875 | */ |
---|
876 | public static String unbackQuoteChars(String string) { |
---|
877 | |
---|
878 | int index; |
---|
879 | StringBuffer newStringBuffer; |
---|
880 | |
---|
881 | // replace each of the following characters with the backquoted version |
---|
882 | String charsFind[] = {"\\\\", "\\'", "\\t", "\\n", "\\r", "\\\"", "\\%"}; |
---|
883 | char charsReplace[] = {'\\', '\'', '\t', '\n', '\r', '"', '%'}; |
---|
884 | int pos[] = new int[charsFind.length]; |
---|
885 | int curPos; |
---|
886 | |
---|
887 | String str = new String(string); |
---|
888 | newStringBuffer = new StringBuffer(); |
---|
889 | while (str.length() > 0) { |
---|
890 | // get positions and closest character to replace |
---|
891 | curPos = str.length(); |
---|
892 | index = -1; |
---|
893 | for (int i = 0; i < pos.length; i++) { |
---|
894 | pos[i] = str.indexOf(charsFind[i]); |
---|
895 | if ( (pos[i] > -1) && (pos[i] < curPos) ) { |
---|
896 | index = i; |
---|
897 | curPos = pos[i]; |
---|
898 | } |
---|
899 | } |
---|
900 | |
---|
901 | // replace character if found, otherwise finished |
---|
902 | if (index == -1) { |
---|
903 | newStringBuffer.append(str); |
---|
904 | str = ""; |
---|
905 | } |
---|
906 | else { |
---|
907 | newStringBuffer.append(str.substring(0, pos[index])); |
---|
908 | newStringBuffer.append(charsReplace[index]); |
---|
909 | str = str.substring(pos[index] + charsFind[index].length()); |
---|
910 | } |
---|
911 | } |
---|
912 | |
---|
913 | return newStringBuffer.toString(); |
---|
914 | } |
---|
915 | |
---|
916 | /** |
---|
917 | * Split up a string containing options into an array of strings, |
---|
918 | * one for each option. |
---|
919 | * |
---|
920 | * @param quotedOptionString the string containing the options |
---|
921 | * @return the array of options |
---|
922 | * @throws Exception in case of an unterminated string, unknown character or |
---|
923 | * a parse error |
---|
924 | */ |
---|
925 | public static String[] splitOptions(String quotedOptionString) throws Exception{ |
---|
926 | |
---|
927 | Vector<String> optionsVec = new Vector<String>(); |
---|
928 | String str = new String(quotedOptionString); |
---|
929 | int i; |
---|
930 | |
---|
931 | while (true){ |
---|
932 | |
---|
933 | //trimLeft |
---|
934 | i = 0; |
---|
935 | while ((i < str.length()) && (Character.isWhitespace(str.charAt(i)))) i++; |
---|
936 | str = str.substring(i); |
---|
937 | |
---|
938 | //stop when str is empty |
---|
939 | if (str.length() == 0) break; |
---|
940 | |
---|
941 | //if str start with a double quote |
---|
942 | if (str.charAt(0) == '"'){ |
---|
943 | |
---|
944 | //find the first not anti-slached double quote |
---|
945 | i = 1; |
---|
946 | while(i < str.length()){ |
---|
947 | if (str.charAt(i) == str.charAt(0)) break; |
---|
948 | if (str.charAt(i) == '\\'){ |
---|
949 | i += 1; |
---|
950 | if (i >= str.length()) |
---|
951 | throw new Exception("String should not finish with \\"); |
---|
952 | } |
---|
953 | i += 1; |
---|
954 | } |
---|
955 | if (i >= str.length()) throw new Exception("Quote parse error."); |
---|
956 | |
---|
957 | //add the founded string to the option vector (without quotes) |
---|
958 | String optStr = str.substring(1,i); |
---|
959 | optStr = unbackQuoteChars(optStr); |
---|
960 | optionsVec.addElement(optStr); |
---|
961 | str = str.substring(i+1); |
---|
962 | } else { |
---|
963 | //find first whiteSpace |
---|
964 | i=0; |
---|
965 | while((i < str.length()) && (!Character.isWhitespace(str.charAt(i)))) i++; |
---|
966 | |
---|
967 | //add the founded string to the option vector |
---|
968 | String optStr = str.substring(0,i); |
---|
969 | optionsVec.addElement(optStr); |
---|
970 | str = str.substring(i); |
---|
971 | } |
---|
972 | } |
---|
973 | |
---|
974 | //convert optionsVec to an array of String |
---|
975 | String[] options = new String[optionsVec.size()]; |
---|
976 | for (i = 0; i < optionsVec.size(); i++) { |
---|
977 | options[i] = (String)optionsVec.elementAt(i); |
---|
978 | } |
---|
979 | return options; |
---|
980 | } |
---|
981 | |
---|
982 | /** |
---|
983 | * Joins all the options in an option array into a single string, |
---|
984 | * as might be used on the command line. |
---|
985 | * |
---|
986 | * @param optionArray the array of options |
---|
987 | * @return the string containing all options. |
---|
988 | */ |
---|
989 | public static String joinOptions(String[] optionArray) { |
---|
990 | |
---|
991 | String optionString = ""; |
---|
992 | for (int i = 0; i < optionArray.length; i++) { |
---|
993 | if (optionArray[i].equals("")) { |
---|
994 | continue; |
---|
995 | } |
---|
996 | boolean escape = false; |
---|
997 | for (int n = 0; n < optionArray[i].length(); n++) { |
---|
998 | if (Character.isWhitespace(optionArray[i].charAt(n))) { |
---|
999 | escape = true; |
---|
1000 | break; |
---|
1001 | } |
---|
1002 | } |
---|
1003 | if (escape) { |
---|
1004 | optionString += '"' + backQuoteChars(optionArray[i]) + '"'; |
---|
1005 | } else { |
---|
1006 | optionString += optionArray[i]; |
---|
1007 | } |
---|
1008 | optionString += " "; |
---|
1009 | } |
---|
1010 | return optionString.trim(); |
---|
1011 | } |
---|
1012 | |
---|
1013 | /** |
---|
1014 | * Creates a new instance of an object given it's class name and |
---|
1015 | * (optional) arguments to pass to it's setOptions method. If the |
---|
1016 | * object implements OptionHandler and the options parameter is |
---|
1017 | * non-null, the object will have it's options set. Example use:<p> |
---|
1018 | * |
---|
1019 | * <code> <pre> |
---|
1020 | * String classifierName = Utils.getOption('W', options); |
---|
1021 | * Classifier c = (Classifier)Utils.forName(Classifier.class, |
---|
1022 | * classifierName, |
---|
1023 | * options); |
---|
1024 | * setClassifier(c); |
---|
1025 | * </pre></code> |
---|
1026 | * |
---|
1027 | * @param classType the class that the instantiated object should |
---|
1028 | * be assignable to -- an exception is thrown if this is not the case |
---|
1029 | * @param className the fully qualified class name of the object |
---|
1030 | * @param options an array of options suitable for passing to setOptions. May |
---|
1031 | * be null. Any options accepted by the object will be removed from the |
---|
1032 | * array. |
---|
1033 | * @return the newly created object, ready for use. |
---|
1034 | * @exception Exception if the class name is invalid, or if the |
---|
1035 | * class is not assignable to the desired class type, or the options |
---|
1036 | * supplied are not acceptable to the object |
---|
1037 | */ |
---|
1038 | public static Object forName(Class<?> classType, |
---|
1039 | String className, |
---|
1040 | String[] options) throws Exception { |
---|
1041 | |
---|
1042 | Class<?> c = null; |
---|
1043 | try { |
---|
1044 | c = Class.forName(className); |
---|
1045 | } catch (Exception ex) { |
---|
1046 | throw new Exception("Can't find class called: " + className); |
---|
1047 | } |
---|
1048 | if (!classType.isAssignableFrom(c)) { |
---|
1049 | throw new Exception(classType.getName() + " is not assignable from " |
---|
1050 | + className); |
---|
1051 | } |
---|
1052 | Object o = c.newInstance(); |
---|
1053 | if ((o instanceof OptionHandler) |
---|
1054 | && (options != null)) { |
---|
1055 | ((OptionHandler)o).setOptions(options); |
---|
1056 | Utils.checkForRemainingOptions(options); |
---|
1057 | } |
---|
1058 | return o; |
---|
1059 | } |
---|
1060 | |
---|
1061 | /** |
---|
1062 | * Generates a commandline of the given object. If the object is not |
---|
1063 | * implementing OptionHandler, then it will only return the classname, |
---|
1064 | * otherwise also the options. |
---|
1065 | * |
---|
1066 | * @param obj the object to turn into a commandline |
---|
1067 | * @return the commandline |
---|
1068 | */ |
---|
1069 | public static String toCommandLine(Object obj) { |
---|
1070 | StringBuffer result; |
---|
1071 | |
---|
1072 | result = new StringBuffer(); |
---|
1073 | |
---|
1074 | if (obj != null) { |
---|
1075 | result.append(obj.getClass().getName()); |
---|
1076 | if (obj instanceof OptionHandler) |
---|
1077 | result.append(" " + joinOptions(((OptionHandler) obj).getOptions())); |
---|
1078 | } |
---|
1079 | |
---|
1080 | return result.toString().trim(); |
---|
1081 | } |
---|
1082 | |
---|
1083 | /** |
---|
1084 | * Computes entropy for an array of integers. |
---|
1085 | * |
---|
1086 | * @param counts array of counts |
---|
1087 | * @return - a log2 a - b log2 b - c log2 c + (a+b+c) log2 (a+b+c) |
---|
1088 | * when given array [a b c] |
---|
1089 | */ |
---|
1090 | public static /*@pure@*/ double info(int counts[]) { |
---|
1091 | |
---|
1092 | int total = 0; |
---|
1093 | double x = 0; |
---|
1094 | for (int j = 0; j < counts.length; j++) { |
---|
1095 | x -= xlogx(counts[j]); |
---|
1096 | total += counts[j]; |
---|
1097 | } |
---|
1098 | return x + xlogx(total); |
---|
1099 | } |
---|
1100 | |
---|
1101 | /** |
---|
1102 | * Tests if a is smaller or equal to b. |
---|
1103 | * |
---|
1104 | * @param a a double |
---|
1105 | * @param b a double |
---|
1106 | */ |
---|
1107 | public static /*@pure@*/ boolean smOrEq(double a,double b) { |
---|
1108 | |
---|
1109 | return (a-b < SMALL); |
---|
1110 | } |
---|
1111 | |
---|
1112 | /** |
---|
1113 | * Tests if a is greater or equal to b. |
---|
1114 | * |
---|
1115 | * @param a a double |
---|
1116 | * @param b a double |
---|
1117 | */ |
---|
1118 | public static /*@pure@*/ boolean grOrEq(double a,double b) { |
---|
1119 | |
---|
1120 | return (b-a < SMALL); |
---|
1121 | } |
---|
1122 | |
---|
1123 | /** |
---|
1124 | * Tests if a is smaller than b. |
---|
1125 | * |
---|
1126 | * @param a a double |
---|
1127 | * @param b a double |
---|
1128 | */ |
---|
1129 | public static /*@pure@*/ boolean sm(double a,double b) { |
---|
1130 | |
---|
1131 | return (b-a > SMALL); |
---|
1132 | } |
---|
1133 | |
---|
1134 | /** |
---|
1135 | * Tests if a is greater than b. |
---|
1136 | * |
---|
1137 | * @param a a double |
---|
1138 | * @param b a double |
---|
1139 | */ |
---|
1140 | public static /*@pure@*/ boolean gr(double a,double b) { |
---|
1141 | |
---|
1142 | return (a-b > SMALL); |
---|
1143 | } |
---|
1144 | |
---|
1145 | /** |
---|
1146 | * Returns the kth-smallest value in the array. |
---|
1147 | * |
---|
1148 | * @param array the array of integers |
---|
1149 | * @param k the value of k |
---|
1150 | * @return the kth-smallest value |
---|
1151 | */ |
---|
1152 | public static double kthSmallestValue(int[] array, int k) { |
---|
1153 | |
---|
1154 | int[] index = new int[array.length]; |
---|
1155 | |
---|
1156 | for (int i = 0; i < index.length; i++) { |
---|
1157 | index[i] = i; |
---|
1158 | } |
---|
1159 | |
---|
1160 | return array[index[select(array, index, 0, array.length - 1, k)]]; |
---|
1161 | } |
---|
1162 | |
---|
1163 | /** |
---|
1164 | * Returns the kth-smallest value in the array |
---|
1165 | * |
---|
1166 | * @param array the array of double |
---|
1167 | * @param k the value of k |
---|
1168 | * @return the kth-smallest value |
---|
1169 | */ |
---|
1170 | public static double kthSmallestValue(double[] array, int k) { |
---|
1171 | |
---|
1172 | int[] index = new int[array.length]; |
---|
1173 | |
---|
1174 | for (int i = 0; i < index.length; i++) { |
---|
1175 | index[i] = i; |
---|
1176 | } |
---|
1177 | |
---|
1178 | return array[index[select(array, index, 0, array.length - 1, k)]]; |
---|
1179 | } |
---|
1180 | |
---|
1181 | /** |
---|
1182 | * Returns the logarithm of a for base 2. |
---|
1183 | * |
---|
1184 | * @param a a double |
---|
1185 | * @return the logarithm for base 2 |
---|
1186 | */ |
---|
1187 | public static /*@pure@*/ double log2(double a) { |
---|
1188 | |
---|
1189 | return Math.log(a) / log2; |
---|
1190 | } |
---|
1191 | |
---|
1192 | /** |
---|
1193 | * Returns index of maximum element in a given |
---|
1194 | * array of doubles. First maximum is returned. |
---|
1195 | * |
---|
1196 | * @param doubles the array of doubles |
---|
1197 | * @return the index of the maximum element |
---|
1198 | */ |
---|
1199 | public static /*@pure@*/ int maxIndex(double[] doubles) { |
---|
1200 | |
---|
1201 | double maximum = 0; |
---|
1202 | int maxIndex = 0; |
---|
1203 | |
---|
1204 | for (int i = 0; i < doubles.length; i++) { |
---|
1205 | if ((i == 0) || (doubles[i] > maximum)) { |
---|
1206 | maxIndex = i; |
---|
1207 | maximum = doubles[i]; |
---|
1208 | } |
---|
1209 | } |
---|
1210 | |
---|
1211 | return maxIndex; |
---|
1212 | } |
---|
1213 | |
---|
1214 | /** |
---|
1215 | * Returns index of maximum element in a given |
---|
1216 | * array of integers. First maximum is returned. |
---|
1217 | * |
---|
1218 | * @param ints the array of integers |
---|
1219 | * @return the index of the maximum element |
---|
1220 | */ |
---|
1221 | public static /*@pure@*/ int maxIndex(int[] ints) { |
---|
1222 | |
---|
1223 | int maximum = 0; |
---|
1224 | int maxIndex = 0; |
---|
1225 | |
---|
1226 | for (int i = 0; i < ints.length; i++) { |
---|
1227 | if ((i == 0) || (ints[i] > maximum)) { |
---|
1228 | maxIndex = i; |
---|
1229 | maximum = ints[i]; |
---|
1230 | } |
---|
1231 | } |
---|
1232 | |
---|
1233 | return maxIndex; |
---|
1234 | } |
---|
1235 | |
---|
1236 | /** |
---|
1237 | * Computes the mean for an array of doubles. |
---|
1238 | * |
---|
1239 | * @param vector the array |
---|
1240 | * @return the mean |
---|
1241 | */ |
---|
1242 | public static /*@pure@*/ double mean(double[] vector) { |
---|
1243 | |
---|
1244 | double sum = 0; |
---|
1245 | |
---|
1246 | if (vector.length == 0) { |
---|
1247 | return 0; |
---|
1248 | } |
---|
1249 | for (int i = 0; i < vector.length; i++) { |
---|
1250 | sum += vector[i]; |
---|
1251 | } |
---|
1252 | return sum / (double) vector.length; |
---|
1253 | } |
---|
1254 | |
---|
1255 | /** |
---|
1256 | * Returns index of minimum element in a given |
---|
1257 | * array of integers. First minimum is returned. |
---|
1258 | * |
---|
1259 | * @param ints the array of integers |
---|
1260 | * @return the index of the minimum element |
---|
1261 | */ |
---|
1262 | public static /*@pure@*/ int minIndex(int[] ints) { |
---|
1263 | |
---|
1264 | int minimum = 0; |
---|
1265 | int minIndex = 0; |
---|
1266 | |
---|
1267 | for (int i = 0; i < ints.length; i++) { |
---|
1268 | if ((i == 0) || (ints[i] < minimum)) { |
---|
1269 | minIndex = i; |
---|
1270 | minimum = ints[i]; |
---|
1271 | } |
---|
1272 | } |
---|
1273 | |
---|
1274 | return minIndex; |
---|
1275 | } |
---|
1276 | |
---|
1277 | /** |
---|
1278 | * Returns index of minimum element in a given |
---|
1279 | * array of doubles. First minimum is returned. |
---|
1280 | * |
---|
1281 | * @param doubles the array of doubles |
---|
1282 | * @return the index of the minimum element |
---|
1283 | */ |
---|
1284 | public static /*@pure@*/ int minIndex(double[] doubles) { |
---|
1285 | |
---|
1286 | double minimum = 0; |
---|
1287 | int minIndex = 0; |
---|
1288 | |
---|
1289 | for (int i = 0; i < doubles.length; i++) { |
---|
1290 | if ((i == 0) || (doubles[i] < minimum)) { |
---|
1291 | minIndex = i; |
---|
1292 | minimum = doubles[i]; |
---|
1293 | } |
---|
1294 | } |
---|
1295 | |
---|
1296 | return minIndex; |
---|
1297 | } |
---|
1298 | |
---|
1299 | /** |
---|
1300 | * Normalizes the doubles in the array by their sum. |
---|
1301 | * |
---|
1302 | * @param doubles the array of double |
---|
1303 | * @exception IllegalArgumentException if sum is Zero or NaN |
---|
1304 | */ |
---|
1305 | public static void normalize(double[] doubles) { |
---|
1306 | |
---|
1307 | double sum = 0; |
---|
1308 | for (int i = 0; i < doubles.length; i++) { |
---|
1309 | sum += doubles[i]; |
---|
1310 | } |
---|
1311 | normalize(doubles, sum); |
---|
1312 | } |
---|
1313 | |
---|
1314 | /** |
---|
1315 | * Normalizes the doubles in the array using the given value. |
---|
1316 | * |
---|
1317 | * @param doubles the array of double |
---|
1318 | * @param sum the value by which the doubles are to be normalized |
---|
1319 | * @exception IllegalArgumentException if sum is zero or NaN |
---|
1320 | */ |
---|
1321 | public static void normalize(double[] doubles, double sum) { |
---|
1322 | |
---|
1323 | if (Double.isNaN(sum)) { |
---|
1324 | throw new IllegalArgumentException("Can't normalize array. Sum is NaN."); |
---|
1325 | } |
---|
1326 | if (sum == 0) { |
---|
1327 | // Maybe this should just be a return. |
---|
1328 | throw new IllegalArgumentException("Can't normalize array. Sum is zero."); |
---|
1329 | } |
---|
1330 | for (int i = 0; i < doubles.length; i++) { |
---|
1331 | doubles[i] /= sum; |
---|
1332 | } |
---|
1333 | } |
---|
1334 | |
---|
1335 | /** |
---|
1336 | * Converts an array containing the natural logarithms of |
---|
1337 | * probabilities stored in a vector back into probabilities. |
---|
1338 | * The probabilities are assumed to sum to one. |
---|
1339 | * |
---|
1340 | * @param a an array holding the natural logarithms of the probabilities |
---|
1341 | * @return the converted array |
---|
1342 | */ |
---|
1343 | public static double[] logs2probs(double[] a) { |
---|
1344 | |
---|
1345 | double max = a[maxIndex(a)]; |
---|
1346 | double sum = 0.0; |
---|
1347 | |
---|
1348 | double[] result = new double[a.length]; |
---|
1349 | for(int i = 0; i < a.length; i++) { |
---|
1350 | result[i] = Math.exp(a[i] - max); |
---|
1351 | sum += result[i]; |
---|
1352 | } |
---|
1353 | |
---|
1354 | normalize(result, sum); |
---|
1355 | |
---|
1356 | return result; |
---|
1357 | } |
---|
1358 | |
---|
1359 | /** |
---|
1360 | * Returns the log-odds for a given probabilitiy. |
---|
1361 | * |
---|
1362 | * @param prob the probabilitiy |
---|
1363 | * |
---|
1364 | * @return the log-odds after the probability has been mapped to |
---|
1365 | * [Utils.SMALL, 1-Utils.SMALL] |
---|
1366 | */ |
---|
1367 | public static /*@pure@*/ double probToLogOdds(double prob) { |
---|
1368 | |
---|
1369 | if (gr(prob, 1) || (sm(prob, 0))) { |
---|
1370 | throw new IllegalArgumentException("probToLogOdds: probability must " + |
---|
1371 | "be in [0,1] "+prob); |
---|
1372 | } |
---|
1373 | double p = SMALL + (1.0 - 2 * SMALL) * prob; |
---|
1374 | return Math.log(p / (1 - p)); |
---|
1375 | } |
---|
1376 | |
---|
1377 | /** |
---|
1378 | * Rounds a double to the next nearest integer value. The JDK version |
---|
1379 | * of it doesn't work properly. |
---|
1380 | * |
---|
1381 | * @param value the double value |
---|
1382 | * @return the resulting integer value |
---|
1383 | */ |
---|
1384 | public static /*@pure@*/ int round(double value) { |
---|
1385 | |
---|
1386 | int roundedValue = value > 0 |
---|
1387 | ? (int)(value + 0.5) |
---|
1388 | : -(int)(Math.abs(value) + 0.5); |
---|
1389 | |
---|
1390 | return roundedValue; |
---|
1391 | } |
---|
1392 | |
---|
1393 | /** |
---|
1394 | * Rounds a double to the next nearest integer value in a probabilistic |
---|
1395 | * fashion (e.g. 0.8 has a 20% chance of being rounded down to 0 and a |
---|
1396 | * 80% chance of being rounded up to 1). In the limit, the average of |
---|
1397 | * the rounded numbers generated by this procedure should converge to |
---|
1398 | * the original double. |
---|
1399 | * |
---|
1400 | * @param value the double value |
---|
1401 | * @param rand the random number generator |
---|
1402 | * @return the resulting integer value |
---|
1403 | */ |
---|
1404 | public static int probRound(double value, Random rand) { |
---|
1405 | |
---|
1406 | if (value >= 0) { |
---|
1407 | double lower = Math.floor(value); |
---|
1408 | double prob = value - lower; |
---|
1409 | if (rand.nextDouble() < prob) { |
---|
1410 | return (int)lower + 1; |
---|
1411 | } else { |
---|
1412 | return (int)lower; |
---|
1413 | } |
---|
1414 | } else { |
---|
1415 | double lower = Math.floor(Math.abs(value)); |
---|
1416 | double prob = Math.abs(value) - lower; |
---|
1417 | if (rand.nextDouble() < prob) { |
---|
1418 | return -((int)lower + 1); |
---|
1419 | } else { |
---|
1420 | return -(int)lower; |
---|
1421 | } |
---|
1422 | } |
---|
1423 | } |
---|
1424 | |
---|
1425 | /** |
---|
1426 | * Rounds a double to the given number of decimal places. |
---|
1427 | * |
---|
1428 | * @param value the double value |
---|
1429 | * @param afterDecimalPoint the number of digits after the decimal point |
---|
1430 | * @return the double rounded to the given precision |
---|
1431 | */ |
---|
1432 | public static /*@pure@*/ double roundDouble(double value,int afterDecimalPoint) { |
---|
1433 | |
---|
1434 | double mask = Math.pow(10.0, (double)afterDecimalPoint); |
---|
1435 | |
---|
1436 | return (double)(Math.round(value * mask)) / mask; |
---|
1437 | } |
---|
1438 | |
---|
1439 | /** |
---|
1440 | * Sorts a given array of integers in ascending order and returns an |
---|
1441 | * array of integers with the positions of the elements of the original |
---|
1442 | * array in the sorted array. The sort is stable. (Equal elements remain |
---|
1443 | * in their original order.) |
---|
1444 | * |
---|
1445 | * @param array this array is not changed by the method! |
---|
1446 | * @return an array of integers with the positions in the sorted |
---|
1447 | * array. |
---|
1448 | */ |
---|
1449 | public static /*@pure@*/ int[] sort(int[] array) { |
---|
1450 | |
---|
1451 | int[] index = new int[array.length]; |
---|
1452 | int[] newIndex = new int[array.length]; |
---|
1453 | int[] helpIndex; |
---|
1454 | int numEqual; |
---|
1455 | |
---|
1456 | for (int i = 0; i < index.length; i++) { |
---|
1457 | index[i] = i; |
---|
1458 | } |
---|
1459 | quickSort(array, index, 0, array.length - 1); |
---|
1460 | |
---|
1461 | // Make sort stable |
---|
1462 | int i = 0; |
---|
1463 | while (i < index.length) { |
---|
1464 | numEqual = 1; |
---|
1465 | for (int j = i + 1; ((j < index.length) |
---|
1466 | && (array[index[i]] == array[index[j]])); |
---|
1467 | j++) { |
---|
1468 | numEqual++; |
---|
1469 | } |
---|
1470 | if (numEqual > 1) { |
---|
1471 | helpIndex = new int[numEqual]; |
---|
1472 | for (int j = 0; j < numEqual; j++) { |
---|
1473 | helpIndex[j] = i + j; |
---|
1474 | } |
---|
1475 | quickSort(index, helpIndex, 0, numEqual - 1); |
---|
1476 | for (int j = 0; j < numEqual; j++) { |
---|
1477 | newIndex[i + j] = index[helpIndex[j]]; |
---|
1478 | } |
---|
1479 | i += numEqual; |
---|
1480 | } else { |
---|
1481 | newIndex[i] = index[i]; |
---|
1482 | i++; |
---|
1483 | } |
---|
1484 | } |
---|
1485 | return newIndex; |
---|
1486 | } |
---|
1487 | |
---|
1488 | /** |
---|
1489 | * Sorts a given array of doubles in ascending order and returns an |
---|
1490 | * array of integers with the positions of the elements of the |
---|
1491 | * original array in the sorted array. NOTE THESE CHANGES: the sort |
---|
1492 | * is no longer stable and it doesn't use safe floating-point |
---|
1493 | * comparisons anymore. Occurrences of Double.NaN are treated as |
---|
1494 | * Double.MAX_VALUE |
---|
1495 | * |
---|
1496 | * @param array this array is not changed by the method! |
---|
1497 | * @return an array of integers with the positions in the sorted |
---|
1498 | * array. |
---|
1499 | */ |
---|
1500 | public static /*@pure@*/ int[] sort(/*@non_null@*/ double[] array) { |
---|
1501 | |
---|
1502 | int[] index = new int[array.length]; |
---|
1503 | array = (double[])array.clone(); |
---|
1504 | for (int i = 0; i < index.length; i++) { |
---|
1505 | index[i] = i; |
---|
1506 | if (Double.isNaN(array[i])) { |
---|
1507 | array[i] = Double.MAX_VALUE; |
---|
1508 | } |
---|
1509 | } |
---|
1510 | quickSort(array, index, 0, array.length - 1); |
---|
1511 | return index; |
---|
1512 | } |
---|
1513 | |
---|
1514 | /** |
---|
1515 | * Sorts a given array of doubles in ascending order and returns an |
---|
1516 | * array of integers with the positions of the elements of the original |
---|
1517 | * array in the sorted array. The sort is stable (Equal elements remain |
---|
1518 | * in their original order.) Occurrences of Double.NaN are treated as |
---|
1519 | * Double.MAX_VALUE |
---|
1520 | * |
---|
1521 | * @param array this array is not changed by the method! |
---|
1522 | * @return an array of integers with the positions in the sorted |
---|
1523 | * array. |
---|
1524 | */ |
---|
1525 | public static /*@pure@*/ int[] stableSort(double[] array){ |
---|
1526 | |
---|
1527 | int[] index = new int[array.length]; |
---|
1528 | int[] newIndex = new int[array.length]; |
---|
1529 | int[] helpIndex; |
---|
1530 | int numEqual; |
---|
1531 | |
---|
1532 | array = (double[])array.clone(); |
---|
1533 | for (int i = 0; i < index.length; i++) { |
---|
1534 | index[i] = i; |
---|
1535 | if (Double.isNaN(array[i])) { |
---|
1536 | array[i] = Double.MAX_VALUE; |
---|
1537 | } |
---|
1538 | } |
---|
1539 | quickSort(array,index,0,array.length-1); |
---|
1540 | |
---|
1541 | // Make sort stable |
---|
1542 | |
---|
1543 | int i = 0; |
---|
1544 | while (i < index.length) { |
---|
1545 | numEqual = 1; |
---|
1546 | for (int j = i+1; ((j < index.length) && Utils.eq(array[index[i]], |
---|
1547 | array[index[j]])); j++) |
---|
1548 | numEqual++; |
---|
1549 | if (numEqual > 1) { |
---|
1550 | helpIndex = new int[numEqual]; |
---|
1551 | for (int j = 0; j < numEqual; j++) |
---|
1552 | helpIndex[j] = i+j; |
---|
1553 | quickSort(index, helpIndex, 0, numEqual-1); |
---|
1554 | for (int j = 0; j < numEqual; j++) |
---|
1555 | newIndex[i+j] = index[helpIndex[j]]; |
---|
1556 | i += numEqual; |
---|
1557 | } else { |
---|
1558 | newIndex[i] = index[i]; |
---|
1559 | i++; |
---|
1560 | } |
---|
1561 | } |
---|
1562 | |
---|
1563 | return newIndex; |
---|
1564 | } |
---|
1565 | |
---|
1566 | /** |
---|
1567 | * Computes the variance for an array of doubles. |
---|
1568 | * |
---|
1569 | * @param vector the array |
---|
1570 | * @return the variance |
---|
1571 | */ |
---|
1572 | public static /*@pure@*/ double variance(double[] vector) { |
---|
1573 | |
---|
1574 | double sum = 0, sumSquared = 0; |
---|
1575 | |
---|
1576 | if (vector.length <= 1) { |
---|
1577 | return 0; |
---|
1578 | } |
---|
1579 | for (int i = 0; i < vector.length; i++) { |
---|
1580 | sum += vector[i]; |
---|
1581 | sumSquared += (vector[i] * vector[i]); |
---|
1582 | } |
---|
1583 | double result = (sumSquared - (sum * sum / (double) vector.length)) / |
---|
1584 | (double) (vector.length - 1); |
---|
1585 | |
---|
1586 | // We don't like negative variance |
---|
1587 | if (result < 0) { |
---|
1588 | return 0; |
---|
1589 | } else { |
---|
1590 | return result; |
---|
1591 | } |
---|
1592 | } |
---|
1593 | |
---|
1594 | /** |
---|
1595 | * Computes the sum of the elements of an array of doubles. |
---|
1596 | * |
---|
1597 | * @param doubles the array of double |
---|
1598 | * @return the sum of the elements |
---|
1599 | */ |
---|
1600 | public static /*@pure@*/ double sum(double[] doubles) { |
---|
1601 | |
---|
1602 | double sum = 0; |
---|
1603 | |
---|
1604 | for (int i = 0; i < doubles.length; i++) { |
---|
1605 | sum += doubles[i]; |
---|
1606 | } |
---|
1607 | return sum; |
---|
1608 | } |
---|
1609 | |
---|
1610 | /** |
---|
1611 | * Computes the sum of the elements of an array of integers. |
---|
1612 | * |
---|
1613 | * @param ints the array of integers |
---|
1614 | * @return the sum of the elements |
---|
1615 | */ |
---|
1616 | public static /*@pure@*/ int sum(int[] ints) { |
---|
1617 | |
---|
1618 | int sum = 0; |
---|
1619 | |
---|
1620 | for (int i = 0; i < ints.length; i++) { |
---|
1621 | sum += ints[i]; |
---|
1622 | } |
---|
1623 | return sum; |
---|
1624 | } |
---|
1625 | |
---|
1626 | /** |
---|
1627 | * Returns c*log2(c) for a given integer value c. |
---|
1628 | * |
---|
1629 | * @param c an integer value |
---|
1630 | * @return c*log2(c) (but is careful to return 0 if c is 0) |
---|
1631 | */ |
---|
1632 | public static /*@pure@*/ double xlogx(int c) { |
---|
1633 | |
---|
1634 | if (c == 0) { |
---|
1635 | return 0.0; |
---|
1636 | } |
---|
1637 | return c * Utils.log2((double) c); |
---|
1638 | } |
---|
1639 | |
---|
1640 | /** |
---|
1641 | * Partitions the instances around a pivot. Used by quicksort and |
---|
1642 | * kthSmallestValue. |
---|
1643 | * |
---|
1644 | * @param array the array of doubles to be sorted |
---|
1645 | * @param index the index into the array of doubles |
---|
1646 | * @param l the first index of the subset |
---|
1647 | * @param r the last index of the subset |
---|
1648 | * |
---|
1649 | * @return the index of the middle element |
---|
1650 | */ |
---|
1651 | private static int partition(double[] array, int[] index, int l, int r) { |
---|
1652 | |
---|
1653 | double pivot = array[index[(l + r) / 2]]; |
---|
1654 | int help; |
---|
1655 | |
---|
1656 | while (l < r) { |
---|
1657 | while ((array[index[l]] < pivot) && (l < r)) { |
---|
1658 | l++; |
---|
1659 | } |
---|
1660 | while ((array[index[r]] > pivot) && (l < r)) { |
---|
1661 | r--; |
---|
1662 | } |
---|
1663 | if (l < r) { |
---|
1664 | help = index[l]; |
---|
1665 | index[l] = index[r]; |
---|
1666 | index[r] = help; |
---|
1667 | l++; |
---|
1668 | r--; |
---|
1669 | } |
---|
1670 | } |
---|
1671 | if ((l == r) && (array[index[r]] > pivot)) { |
---|
1672 | r--; |
---|
1673 | } |
---|
1674 | |
---|
1675 | return r; |
---|
1676 | } |
---|
1677 | |
---|
1678 | /** |
---|
1679 | * Partitions the instances around a pivot. Used by quicksort and |
---|
1680 | * kthSmallestValue. |
---|
1681 | * |
---|
1682 | * @param array the array of integers to be sorted |
---|
1683 | * @param index the index into the array of integers |
---|
1684 | * @param l the first index of the subset |
---|
1685 | * @param r the last index of the subset |
---|
1686 | * |
---|
1687 | * @return the index of the middle element |
---|
1688 | */ |
---|
1689 | private static int partition(int[] array, int[] index, int l, int r) { |
---|
1690 | |
---|
1691 | double pivot = array[index[(l + r) / 2]]; |
---|
1692 | int help; |
---|
1693 | |
---|
1694 | while (l < r) { |
---|
1695 | while ((array[index[l]] < pivot) && (l < r)) { |
---|
1696 | l++; |
---|
1697 | } |
---|
1698 | while ((array[index[r]] > pivot) && (l < r)) { |
---|
1699 | r--; |
---|
1700 | } |
---|
1701 | if (l < r) { |
---|
1702 | help = index[l]; |
---|
1703 | index[l] = index[r]; |
---|
1704 | index[r] = help; |
---|
1705 | l++; |
---|
1706 | r--; |
---|
1707 | } |
---|
1708 | } |
---|
1709 | if ((l == r) && (array[index[r]] > pivot)) { |
---|
1710 | r--; |
---|
1711 | } |
---|
1712 | |
---|
1713 | return r; |
---|
1714 | } |
---|
1715 | |
---|
1716 | /** |
---|
1717 | * Implements quicksort according to Manber's "Introduction to |
---|
1718 | * Algorithms". |
---|
1719 | * |
---|
1720 | * @param array the array of doubles to be sorted |
---|
1721 | * @param index the index into the array of doubles |
---|
1722 | * @param left the first index of the subset to be sorted |
---|
1723 | * @param right the last index of the subset to be sorted |
---|
1724 | */ |
---|
1725 | //@ requires 0 <= first && first <= right && right < array.length; |
---|
1726 | //@ requires (\forall int i; 0 <= i && i < index.length; 0 <= index[i] && index[i] < array.length); |
---|
1727 | //@ requires array != index; |
---|
1728 | // assignable index; |
---|
1729 | private static void quickSort(/*@non_null@*/ double[] array, /*@non_null@*/ int[] index, |
---|
1730 | int left, int right) { |
---|
1731 | |
---|
1732 | if (left < right) { |
---|
1733 | int middle = partition(array, index, left, right); |
---|
1734 | quickSort(array, index, left, middle); |
---|
1735 | quickSort(array, index, middle + 1, right); |
---|
1736 | } |
---|
1737 | } |
---|
1738 | |
---|
1739 | /** |
---|
1740 | * Implements quicksort according to Manber's "Introduction to |
---|
1741 | * Algorithms". |
---|
1742 | * |
---|
1743 | * @param array the array of integers to be sorted |
---|
1744 | * @param index the index into the array of integers |
---|
1745 | * @param left the first index of the subset to be sorted |
---|
1746 | * @param right the last index of the subset to be sorted |
---|
1747 | */ |
---|
1748 | //@ requires 0 <= first && first <= right && right < array.length; |
---|
1749 | //@ requires (\forall int i; 0 <= i && i < index.length; 0 <= index[i] && index[i] < array.length); |
---|
1750 | //@ requires array != index; |
---|
1751 | // assignable index; |
---|
1752 | private static void quickSort(/*@non_null@*/ int[] array, /*@non_null@*/ int[] index, |
---|
1753 | int left, int right) { |
---|
1754 | |
---|
1755 | if (left < right) { |
---|
1756 | int middle = partition(array, index, left, right); |
---|
1757 | quickSort(array, index, left, middle); |
---|
1758 | quickSort(array, index, middle + 1, right); |
---|
1759 | } |
---|
1760 | } |
---|
1761 | |
---|
1762 | /** |
---|
1763 | * Implements computation of the kth-smallest element according |
---|
1764 | * to Manber's "Introduction to Algorithms". |
---|
1765 | * |
---|
1766 | * @param array the array of double |
---|
1767 | * @param index the index into the array of doubles |
---|
1768 | * @param left the first index of the subset |
---|
1769 | * @param right the last index of the subset |
---|
1770 | * @param k the value of k |
---|
1771 | * |
---|
1772 | * @return the index of the kth-smallest element |
---|
1773 | */ |
---|
1774 | //@ requires 0 <= first && first <= right && right < array.length; |
---|
1775 | private static int select(/*@non_null@*/ double[] array, /*@non_null@*/ int[] index, |
---|
1776 | int left, int right, int k) { |
---|
1777 | |
---|
1778 | if (left == right) { |
---|
1779 | return left; |
---|
1780 | } else { |
---|
1781 | int middle = partition(array, index, left, right); |
---|
1782 | if ((middle - left + 1) >= k) { |
---|
1783 | return select(array, index, left, middle, k); |
---|
1784 | } else { |
---|
1785 | return select(array, index, middle + 1, right, k - (middle - left + 1)); |
---|
1786 | } |
---|
1787 | } |
---|
1788 | } |
---|
1789 | |
---|
1790 | /** |
---|
1791 | * Converts a File's absolute path to a path relative to the user |
---|
1792 | * (ie start) directory. Includes an additional workaround for Cygwin, which |
---|
1793 | * doesn't like upper case drive letters. |
---|
1794 | * @param absolute the File to convert to relative path |
---|
1795 | * @return a File with a path that is relative to the user's directory |
---|
1796 | * @exception Exception if the path cannot be constructed |
---|
1797 | */ |
---|
1798 | public static File convertToRelativePath(File absolute) throws Exception { |
---|
1799 | File result; |
---|
1800 | String fileStr; |
---|
1801 | |
---|
1802 | result = null; |
---|
1803 | |
---|
1804 | // if we're running windows, it could be Cygwin |
---|
1805 | if (File.separator.equals("\\")) { |
---|
1806 | // Cygwin doesn't like upper case drives -> try lower case drive |
---|
1807 | try { |
---|
1808 | fileStr = absolute.getPath(); |
---|
1809 | fileStr = fileStr.substring(0, 1).toLowerCase() |
---|
1810 | + fileStr.substring(1); |
---|
1811 | result = createRelativePath(new File(fileStr)); |
---|
1812 | } |
---|
1813 | catch (Exception e) { |
---|
1814 | // no luck with Cygwin workaround, convert it like it is |
---|
1815 | result = createRelativePath(absolute); |
---|
1816 | } |
---|
1817 | } |
---|
1818 | else { |
---|
1819 | result = createRelativePath(absolute); |
---|
1820 | } |
---|
1821 | |
---|
1822 | return result; |
---|
1823 | } |
---|
1824 | |
---|
1825 | /** |
---|
1826 | * Converts a File's absolute path to a path relative to the user |
---|
1827 | * (ie start) directory. |
---|
1828 | * |
---|
1829 | * @param absolute the File to convert to relative path |
---|
1830 | * @return a File with a path that is relative to the user's directory |
---|
1831 | * @exception Exception if the path cannot be constructed |
---|
1832 | */ |
---|
1833 | protected static File createRelativePath(File absolute) throws Exception { |
---|
1834 | File userDir = new File(System.getProperty("user.dir")); |
---|
1835 | String userPath = userDir.getAbsolutePath() + File.separator; |
---|
1836 | String targetPath = (new File(absolute.getParent())).getPath() |
---|
1837 | + File.separator; |
---|
1838 | String fileName = absolute.getName(); |
---|
1839 | StringBuffer relativePath = new StringBuffer(); |
---|
1840 | // relativePath.append("."+File.separator); |
---|
1841 | // System.err.println("User dir "+userPath); |
---|
1842 | // System.err.println("Target path "+targetPath); |
---|
1843 | |
---|
1844 | // file is in user dir (or subdir) |
---|
1845 | int subdir = targetPath.indexOf(userPath); |
---|
1846 | if (subdir == 0) { |
---|
1847 | if (userPath.length() == targetPath.length()) { |
---|
1848 | relativePath.append(fileName); |
---|
1849 | } else { |
---|
1850 | int ll = userPath.length(); |
---|
1851 | relativePath.append(targetPath.substring(ll)); |
---|
1852 | relativePath.append(fileName); |
---|
1853 | } |
---|
1854 | } else { |
---|
1855 | int sepCount = 0; |
---|
1856 | String temp = new String(userPath); |
---|
1857 | while (temp.indexOf(File.separator) != -1) { |
---|
1858 | int ind = temp.indexOf(File.separator); |
---|
1859 | sepCount++; |
---|
1860 | temp = temp.substring(ind+1, temp.length()); |
---|
1861 | } |
---|
1862 | |
---|
1863 | String targetTemp = new String(targetPath); |
---|
1864 | String userTemp = new String(userPath); |
---|
1865 | int tcount = 0; |
---|
1866 | while (targetTemp.indexOf(File.separator) != -1) { |
---|
1867 | int ind = targetTemp.indexOf(File.separator); |
---|
1868 | int ind2 = userTemp.indexOf(File.separator); |
---|
1869 | String tpart = targetTemp.substring(0,ind+1); |
---|
1870 | String upart = userTemp.substring(0,ind2+1); |
---|
1871 | if (tpart.compareTo(upart) != 0) { |
---|
1872 | if (tcount == 0) { |
---|
1873 | tcount = -1; |
---|
1874 | } |
---|
1875 | break; |
---|
1876 | } |
---|
1877 | tcount++; |
---|
1878 | targetTemp = targetTemp.substring(ind+1, targetTemp.length()); |
---|
1879 | userTemp = userTemp.substring(ind2+1, userTemp.length()); |
---|
1880 | } |
---|
1881 | if (tcount == -1) { |
---|
1882 | // then target file is probably on another drive (under windows) |
---|
1883 | throw new Exception("Can't construct a path to file relative to user " |
---|
1884 | +"dir."); |
---|
1885 | } |
---|
1886 | if (targetTemp.indexOf(File.separator) == -1) { |
---|
1887 | targetTemp = ""; |
---|
1888 | } |
---|
1889 | for (int i = 0; i < sepCount - tcount; i++) { |
---|
1890 | relativePath.append(".."+File.separator); |
---|
1891 | } |
---|
1892 | relativePath.append(targetTemp + fileName); |
---|
1893 | } |
---|
1894 | // System.err.println("new path : "+relativePath.toString()); |
---|
1895 | return new File(relativePath.toString()); |
---|
1896 | } |
---|
1897 | |
---|
1898 | /** |
---|
1899 | * Implements computation of the kth-smallest element according |
---|
1900 | * to Manber's "Introduction to Algorithms". |
---|
1901 | * |
---|
1902 | * @param array the array of integers |
---|
1903 | * @param index the index into the array of integers |
---|
1904 | * @param left the first index of the subset |
---|
1905 | * @param right the last index of the subset |
---|
1906 | * @param k the value of k |
---|
1907 | * |
---|
1908 | * @return the index of the kth-smallest element |
---|
1909 | */ |
---|
1910 | //@ requires 0 <= first && first <= right && right < array.length; |
---|
1911 | private static int select(/*@non_null@*/ int[] array, /*@non_null@*/ int[] index, |
---|
1912 | int left, int right, int k) { |
---|
1913 | |
---|
1914 | if (left == right) { |
---|
1915 | return left; |
---|
1916 | } else { |
---|
1917 | int middle = partition(array, index, left, right); |
---|
1918 | if ((middle - left + 1) >= k) { |
---|
1919 | return select(array, index, left, middle, k); |
---|
1920 | } else { |
---|
1921 | return select(array, index, middle + 1, right, k - (middle - left + 1)); |
---|
1922 | } |
---|
1923 | } |
---|
1924 | } |
---|
1925 | |
---|
1926 | /** |
---|
1927 | * Returns the revision string. |
---|
1928 | * |
---|
1929 | * @return the revision |
---|
1930 | */ |
---|
1931 | public String getRevision() { |
---|
1932 | return RevisionUtils.extract("$Revision: 5987 $"); |
---|
1933 | } |
---|
1934 | |
---|
1935 | /** |
---|
1936 | * Main method for testing this class. |
---|
1937 | * |
---|
1938 | * @param ops some dummy options |
---|
1939 | */ |
---|
1940 | public static void main(String[] ops) { |
---|
1941 | |
---|
1942 | double[] doublesWithNaN = {4.5, 6.7, Double.NaN, 3.4, 4.8, 1.2, 3.4}; |
---|
1943 | double[] doubles = {4.5, 6.7, 6.7, 3.4, 4.8, 1.2, 3.4, 6.7, 6.7, 3.4}; |
---|
1944 | int[] ints = {12, 6, 2, 18, 16, 6, 7, 5, 18, 18, 17}; |
---|
1945 | |
---|
1946 | try { |
---|
1947 | |
---|
1948 | // Option handling |
---|
1949 | System.out.println("First option split up:"); |
---|
1950 | if (ops.length > 0) { |
---|
1951 | String[] firstOptionSplitUp = Utils.splitOptions(ops[0]); |
---|
1952 | for (int i = 0; i < firstOptionSplitUp.length; i ++) { |
---|
1953 | System.out.println(firstOptionSplitUp[i]); |
---|
1954 | } |
---|
1955 | } |
---|
1956 | System.out.println("Partitioned options: "); |
---|
1957 | String[] partitionedOptions = Utils.partitionOptions(ops); |
---|
1958 | for (int i = 0; i < partitionedOptions.length; i++) { |
---|
1959 | System.out.println(partitionedOptions[i]); |
---|
1960 | } |
---|
1961 | System.out.println("Get position of flag -f: " + Utils.getOptionPos('f', ops)); |
---|
1962 | System.out.println("Get flag -f: " + Utils.getFlag('f', ops)); |
---|
1963 | System.out.println("Get position of option -o: " + Utils.getOptionPos('o', ops)); |
---|
1964 | System.out.println("Get option -o: " + Utils.getOption('o', ops)); |
---|
1965 | System.out.println("Checking for remaining options... "); |
---|
1966 | Utils.checkForRemainingOptions(ops); |
---|
1967 | |
---|
1968 | // Statistics |
---|
1969 | System.out.println("Original array with NaN (doubles): "); |
---|
1970 | for (int i = 0; i < doublesWithNaN.length; i++) { |
---|
1971 | System.out.print(doublesWithNaN[i] + " "); |
---|
1972 | } |
---|
1973 | System.out.println(); |
---|
1974 | System.out.println("Original array (doubles): "); |
---|
1975 | for (int i = 0; i < doubles.length; i++) { |
---|
1976 | System.out.print(doubles[i] + " "); |
---|
1977 | } |
---|
1978 | System.out.println(); |
---|
1979 | System.out.println("Original array (ints): "); |
---|
1980 | for (int i = 0; i < ints.length; i++) { |
---|
1981 | System.out.print(ints[i] + " "); |
---|
1982 | } |
---|
1983 | System.out.println(); |
---|
1984 | System.out.println("Correlation: " + Utils.correlation(doubles, doubles, |
---|
1985 | doubles.length)); |
---|
1986 | System.out.println("Mean: " + Utils.mean(doubles)); |
---|
1987 | System.out.println("Variance: " + Utils.variance(doubles)); |
---|
1988 | System.out.println("Sum (doubles): " + Utils.sum(doubles)); |
---|
1989 | System.out.println("Sum (ints): " + Utils.sum(ints)); |
---|
1990 | System.out.println("Max index (doubles): " + Utils.maxIndex(doubles)); |
---|
1991 | System.out.println("Max index (ints): " + Utils.maxIndex(ints)); |
---|
1992 | System.out.println("Min index (doubles): " + Utils.minIndex(doubles)); |
---|
1993 | System.out.println("Min index (ints): " + Utils.minIndex(ints)); |
---|
1994 | System.out.println("Median (doubles): " + |
---|
1995 | Utils.kthSmallestValue(doubles, doubles.length / 2)); |
---|
1996 | System.out.println("Median (ints): " + |
---|
1997 | Utils.kthSmallestValue(ints, ints.length / 2)); |
---|
1998 | |
---|
1999 | // Sorting and normalizing |
---|
2000 | System.out.println("Sorted array with NaN (doubles): "); |
---|
2001 | int[] sorted = Utils.sort(doublesWithNaN); |
---|
2002 | for (int i = 0; i < doublesWithNaN.length; i++) { |
---|
2003 | System.out.print(doublesWithNaN[sorted[i]] + " "); |
---|
2004 | } |
---|
2005 | System.out.println(); |
---|
2006 | System.out.println("Sorted array (doubles): "); |
---|
2007 | sorted = Utils.sort(doubles); |
---|
2008 | for (int i = 0; i < doubles.length; i++) { |
---|
2009 | System.out.print(doubles[sorted[i]] + " "); |
---|
2010 | } |
---|
2011 | System.out.println(); |
---|
2012 | System.out.println("Sorted array (ints): "); |
---|
2013 | sorted = Utils.sort(ints); |
---|
2014 | for (int i = 0; i < ints.length; i++) { |
---|
2015 | System.out.print(ints[sorted[i]] + " "); |
---|
2016 | } |
---|
2017 | System.out.println(); |
---|
2018 | System.out.println("Indices from stable sort (doubles): "); |
---|
2019 | sorted = Utils.stableSort(doubles); |
---|
2020 | for (int i = 0; i < doubles.length; i++) { |
---|
2021 | System.out.print(sorted[i] + " "); |
---|
2022 | } |
---|
2023 | System.out.println(); |
---|
2024 | System.out.println("Indices from sort (ints): "); |
---|
2025 | sorted = Utils.sort(ints); |
---|
2026 | for (int i = 0; i < ints.length; i++) { |
---|
2027 | System.out.print(sorted[i] + " "); |
---|
2028 | } |
---|
2029 | System.out.println(); |
---|
2030 | System.out.println("Normalized array (doubles): "); |
---|
2031 | Utils.normalize(doubles); |
---|
2032 | for (int i = 0; i < doubles.length; i++) { |
---|
2033 | System.out.print(doubles[i] + " "); |
---|
2034 | } |
---|
2035 | System.out.println(); |
---|
2036 | System.out.println("Normalized again (doubles): "); |
---|
2037 | Utils.normalize(doubles, Utils.sum(doubles)); |
---|
2038 | for (int i = 0; i < doubles.length; i++) { |
---|
2039 | System.out.print(doubles[i] + " "); |
---|
2040 | } |
---|
2041 | System.out.println(); |
---|
2042 | |
---|
2043 | // Pretty-printing |
---|
2044 | System.out.println("-4.58: " + Utils.doubleToString(-4.57826535, 2)); |
---|
2045 | System.out.println("-6.78: " + Utils.doubleToString(-6.78214234, 6,2)); |
---|
2046 | |
---|
2047 | // Comparisons |
---|
2048 | System.out.println("5.70001 == 5.7 ? " + Utils.eq(5.70001, 5.7)); |
---|
2049 | System.out.println("5.70001 > 5.7 ? " + Utils.gr(5.70001, 5.7)); |
---|
2050 | System.out.println("5.70001 >= 5.7 ? " + Utils.grOrEq(5.70001, 5.7)); |
---|
2051 | System.out.println("5.7 < 5.70001 ? " + Utils.sm(5.7, 5.70001)); |
---|
2052 | System.out.println("5.7 <= 5.70001 ? " + Utils.smOrEq(5.7, 5.70001)); |
---|
2053 | |
---|
2054 | // Math |
---|
2055 | System.out.println("Info (ints): " + Utils.info(ints)); |
---|
2056 | System.out.println("log2(4.6): " + Utils.log2(4.6)); |
---|
2057 | System.out.println("5 * log(5): " + Utils.xlogx(5)); |
---|
2058 | System.out.println("5.5 rounded: " + Utils.round(5.5)); |
---|
2059 | System.out.println("5.55555 rounded to 2 decimal places: " + |
---|
2060 | Utils.roundDouble(5.55555, 2)); |
---|
2061 | |
---|
2062 | // Arrays |
---|
2063 | System.out.println("Array-Dimensions of 'new int[][]': " + Utils.getArrayDimensions(new int[][]{})); |
---|
2064 | System.out.println("Array-Dimensions of 'new int[][]{{1,2,3},{4,5,6}}': " + Utils.getArrayDimensions(new int[][]{{1,2,3},{4,5,6}})); |
---|
2065 | String[][][] s = new String[3][4][]; |
---|
2066 | System.out.println("Array-Dimensions of 'new String[3][4][]': " + Utils.getArrayDimensions(s)); |
---|
2067 | } catch (Exception e) { |
---|
2068 | e.printStackTrace(); |
---|
2069 | } |
---|
2070 | } |
---|
2071 | } |
---|
2072 | |
---|