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.
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.
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.
19
* Copyright (C) 1999-2004 University of Waikato, Hamilton, New Zealand
25
import java.lang.Math;
26
import java.lang.reflect.Array;
27
import java.util.Properties;
29
import java.io.FileInputStream;
30
import java.util.Random;
33
* Class implementing some simple utility methods.
38
* @author Julien Prados
39
* @version $Revision: 1.57 $
41
public final class Utils {
43
/** The natural logarithm of 2. */
44
public static double log2 = Math.log(2);
46
/** The small deviation allowed in double comparisons */
47
public static double SMALL = 1e-6;
51
* Reads properties that inherit from three locations. Properties
52
* are first defined in the system resource location (i.e. in the
53
* CLASSPATH). These default properties must exist. Properties
54
* defined in the users home directory (optional) override default
55
* settings. Properties defined in the current directory (optional)
56
* override all these settings.
58
* @param resourceName the location of the resource that should be
59
* loaded. e.g.: "weka/core/Utils.props". (The use of hardcoded
60
* forward slashes here is OK - see
61
* jdk1.1/docs/guide/misc/resources.html) This routine will also
62
* look for the file (in this case) "Utils.props" in the users home
63
* directory and the current directory.
64
* @return the Properties
65
* @exception Exception if no default properties are defined, or if
66
* an error occurs reading the properties files.
68
public static Properties readProperties(String resourceName)
71
Properties defaultProps = new Properties();
73
// Apparently hardcoded slashes are OK here
74
// jdk1.1/docs/guide/misc/resources.html
75
defaultProps.load(ClassLoader.getSystemResourceAsStream(resourceName));
76
} catch (Exception ex) {
77
/* throw new Exception("Problem reading default properties: "
78
+ ex.getMessage()); */
79
System.err.println("Warning, unable to load properties file from "
80
+"system resource (Utils.java)");
83
// Hardcoded slash is OK here
84
// eg: see jdk1.1/docs/guide/misc/resources.html
85
int slInd = resourceName.lastIndexOf('/');
87
resourceName = resourceName.substring(slInd + 1);
90
// Allow a properties file in the home directory to override
91
Properties userProps = new Properties(defaultProps);
92
File propFile = new File(System.getProperties().getProperty("user.home")
95
if (propFile.exists()) {
97
userProps.load(new FileInputStream(propFile));
98
} catch (Exception ex) {
99
throw new Exception("Problem reading user properties: " + propFile);
103
// Allow a properties file in the current directory to override
104
Properties localProps = new Properties(userProps);
105
propFile = new File(resourceName);
106
if (propFile.exists()) {
108
localProps.load(new FileInputStream(propFile));
109
} catch (Exception ex) {
110
throw new Exception("Problem reading local properties: " + propFile);
118
* Returns the correlation coefficient of two double vectors.
120
* @param y1 double vector 1
121
* @param y2 double vector 2
122
* @param n the length of two double vectors
123
* @return the correlation coefficient
125
public static final double correlation(double y1[],double y2[],int n) {
128
double av1 = 0.0, av2 = 0.0, y11 = 0.0, y22 = 0.0, y12 = 0.0, c;
133
for (i = 0; i < n; i++) {
139
for (i = 0; i < n; i++) {
140
y11 += (y1[i] - av1) * (y1[i] - av1);
141
y22 += (y2[i] - av2) * (y2[i] - av2);
142
y12 += (y1[i] - av1) * (y2[i] - av2);
144
if (y11 * y22 == 0.0) {
147
c = y12 / Math.sqrt(Math.abs(y11 * y22));
154
* Removes all occurrences of a string from another string.
156
* @param inString the string to remove substrings from.
157
* @param substring the substring to remove.
158
* @return the input string with occurrences of substring removed.
160
public static String removeSubstring(String inString, String substring) {
162
StringBuffer result = new StringBuffer();
163
int oldLoc = 0, loc = 0;
164
while ((loc = inString.indexOf(substring, oldLoc))!= -1) {
165
result.append(inString.substring(oldLoc, loc));
166
oldLoc = loc + substring.length();
168
result.append(inString.substring(oldLoc));
169
return result.toString();
173
* Replaces with a new string, all occurrences of a string from
176
* @param inString the string to replace substrings in.
177
* @param subString the substring to replace.
178
* @param replaceString the replacement substring
179
* @return the input string with occurrences of substring replaced.
181
public static String replaceSubstring(String inString, String subString,
182
String replaceString) {
184
StringBuffer result = new StringBuffer();
185
int oldLoc = 0, loc = 0;
186
while ((loc = inString.indexOf(subString, oldLoc))!= -1) {
187
result.append(inString.substring(oldLoc, loc));
188
result.append(replaceString);
189
oldLoc = loc + subString.length();
191
result.append(inString.substring(oldLoc));
192
return result.toString();
197
* Pads a string to a specified length, inserting spaces on the left
198
* as required. If the string is too long, characters are removed (from
201
* @param inString the input string
202
* @param length the desired length of the output string
203
* @return the output string
205
public static String padLeft(String inString, int length) {
207
return fixStringLength(inString, length, false);
211
* Pads a string to a specified length, inserting spaces on the right
212
* as required. If the string is too long, characters are removed (from
215
* @param inString the input string
216
* @param length the desired length of the output string
217
* @return the output string
219
public static String padRight(String inString, int length) {
221
return fixStringLength(inString, length, true);
225
* Pads a string to a specified length, inserting spaces as
226
* required. If the string is too long, characters are removed (from
229
* @param inString the input string
230
* @param length the desired length of the output string
231
* @param right true if inserted spaces should be added to the right
232
* @return the output string
234
private static /*@pure@*/ String fixStringLength(String inString, int length,
237
if (inString.length() < length) {
238
while (inString.length() < length) {
239
inString = (right ? inString.concat(" ") : " ".concat(inString));
241
} else if (inString.length() > length) {
242
inString = inString.substring(0, length);
248
* Rounds a double and converts it into String.
250
* @param value the double value
251
* @param afterDecimalPoint the (maximum) number of digits permitted
252
* after the decimal point
253
* @return the double as a formatted string
255
public static /*@pure@*/ String doubleToString(double value, int afterDecimalPoint) {
257
StringBuffer stringBuffer;
262
temp = value * Math.pow(10.0, afterDecimalPoint);
263
if (Math.abs(temp) < Long.MAX_VALUE) {
264
precisionValue = (temp > 0) ? (long)(temp + 0.5)
265
: -(long)(Math.abs(temp) + 0.5);
266
if (precisionValue == 0) {
267
stringBuffer = new StringBuffer(String.valueOf(0));
269
stringBuffer = new StringBuffer(String.valueOf(precisionValue));
271
if (afterDecimalPoint == 0) {
272
return stringBuffer.toString();
274
dotPosition = stringBuffer.length() - afterDecimalPoint;
275
while (((precisionValue < 0) && (dotPosition < 1)) ||
277
if (precisionValue < 0) {
278
stringBuffer.insert(1, '0');
280
stringBuffer.insert(0, '0');
284
stringBuffer.insert(dotPosition, '.');
285
if ((precisionValue < 0) && (stringBuffer.charAt(1) == '.')) {
286
stringBuffer.insert(1, '0');
287
} else if (stringBuffer.charAt(0) == '.') {
288
stringBuffer.insert(0, '0');
290
int currentPos = stringBuffer.length() - 1;
291
while ((currentPos > dotPosition) &&
292
(stringBuffer.charAt(currentPos) == '0')) {
293
stringBuffer.setCharAt(currentPos--, ' ');
295
if (stringBuffer.charAt(currentPos) == '.') {
296
stringBuffer.setCharAt(currentPos, ' ');
299
return stringBuffer.toString().trim();
301
return new String("" + value);
305
* Rounds a double and converts it into a formatted decimal-justified String.
306
* Trailing 0's are replaced with spaces.
308
* @param value the double value
309
* @param width the width of the string
310
* @param afterDecimalPoint the number of digits after the decimal point
311
* @return the double as a formatted string
313
public static /*@pure@*/ String doubleToString(double value, int width,
314
int afterDecimalPoint) {
316
String tempString = doubleToString(value, afterDecimalPoint);
320
if ((afterDecimalPoint >= width)
321
|| (tempString.indexOf('E') != -1)) { // Protects sci notation
326
result = new char[width];
327
for (int i = 0; i < result.length; i++) {
331
if (afterDecimalPoint > 0) {
332
// Get position of decimal point and insert decimal point
333
dotPosition = tempString.indexOf('.');
334
if (dotPosition == -1) {
335
dotPosition = tempString.length();
337
result[width - afterDecimalPoint - 1] = '.';
340
dotPosition = tempString.length();
344
int offset = width - afterDecimalPoint - dotPosition;
345
if (afterDecimalPoint > 0) {
349
// Not enough room to decimal align within the supplied width
354
// Copy characters before decimal point
355
for (int i = 0; i < dotPosition; i++) {
356
result[offset + i] = tempString.charAt(i);
359
// Copy characters after decimal point
360
for (int i = dotPosition + 1; i < tempString.length(); i++) {
361
result[offset + i] = tempString.charAt(i);
364
return new String(result);
368
* Returns the basic class of an array class (handles multi-dimensional
370
* @param c the array to inspect
371
* @return the class of the innermost elements
373
public static Class getArrayClass(Class c) {
374
if (c.getComponentType().isArray())
375
return getArrayClass(c.getComponentType());
377
return c.getComponentType();
381
* Returns the dimensions of the given array. Even though the
382
* parameter is of type "Object" one can hand over primitve arrays, e.g.
383
* int[3] or double[2][4].
385
* @param array the array to determine the dimensions for
386
* @return the dimensions of the array
388
public static int getArrayDimensions(Class array) {
389
if (array.getComponentType().isArray())
390
return 1 + getArrayDimensions(array.getComponentType());
396
* Returns the dimensions of the given array. Even though the
397
* parameter is of type "Object" one can hand over primitve arrays, e.g.
398
* int[3] or double[2][4].
400
* @param array the array to determine the dimensions for
401
* @return the dimensions of the array
403
public static int getArrayDimensions(Object array) {
404
return getArrayDimensions(array.getClass());
408
* Returns the given Array in a string representation. Even though the
409
* parameter is of type "Object" one can hand over primitve arrays, e.g.
410
* int[3] or double[2][4].
412
* @param array the array to return in a string representation
413
* @return the array as string
415
public static String arrayToString(Object array) {
421
dimensions = getArrayDimensions(array);
423
if (dimensions == 0) {
426
else if (dimensions == 1) {
427
for (i = 0; i < Array.getLength(array); i++) {
430
if (Array.get(array, i) == null)
433
result += Array.get(array, i).toString();
437
for (i = 0; i < Array.getLength(array); i++) {
440
result += "[" + arrayToString(Array.get(array, i)) + "]";
448
* Tests if a is equal to b.
453
public static /*@pure@*/ boolean eq(double a, double b){
455
return (a - b < SMALL) && (b - a < SMALL);
459
* Checks if the given array contains any non-empty options.
461
* @param options an array of strings
462
* @exception Exception if there are any non-empty options
464
public static void checkForRemainingOptions(String[] options)
467
int illegalOptionsFound = 0;
468
StringBuffer text = new StringBuffer();
470
if (options == null) {
473
for (int i = 0; i < options.length; i++) {
474
if (options[i].length() > 0) {
475
illegalOptionsFound++;
476
text.append(options[i] + ' ');
479
if (illegalOptionsFound > 0) {
480
throw new Exception("Illegal options: " + text);
485
* Checks if the given array contains the flag "-Char". Stops
486
* searching at the first marker "--". If the flag is found,
487
* it is replaced with the empty string.
489
* @param flag the character indicating the flag.
490
* @param options the array of strings containing all the options.
491
* @return true if the flag was found
492
* @exception Exception if an illegal option was found
494
public static boolean getFlag(char flag, String[] options)
497
return getFlag("" + flag, options);
501
* Checks if the given array contains the flag "-String". Stops
502
* searching at the first marker "--". If the flag is found,
503
* it is replaced with the empty string.
505
* @param flag the String indicating the flag.
506
* @param options the array of strings containing all the options.
507
* @return true if the flag was found
508
* @exception Exception if an illegal option was found
510
public static boolean getFlag(String flag, String[] options)
513
int pos = getOptionPos(flag, options);
522
* Gets an option indicated by a flag "-Char" from the given array
523
* of strings. Stops searching at the first marker "--". Replaces
524
* flag and option with empty strings.
526
* @param flag the character indicating the option.
527
* @param options the array of strings containing all the options.
528
* @return the indicated option or an empty string
529
* @exception Exception if the option indicated by the flag can't be found
531
public static /*@non_null@*/ String getOption(char flag, String[] options)
534
return getOption("" + flag, options);
538
* Gets an option indicated by a flag "-String" from the given array
539
* of strings. Stops searching at the first marker "--". Replaces
540
* flag and option with empty strings.
542
* @param flag the String indicating the option.
543
* @param options the array of strings containing all the options.
544
* @return the indicated option or an empty string
545
* @exception Exception if the option indicated by the flag can't be found
547
public static /*@non_null@*/ String getOption(String flag, String[] options)
551
int i = getOptionPos(flag, options);
554
if (options[i].equals("-" + flag)) {
555
if (i + 1 == options.length) {
556
throw new Exception("No value given for -" + flag + " option.");
559
newString = new String(options[i + 1]);
563
if (options[i].charAt(1) == '-') {
572
* Gets the index of an option or flag indicated by a flag "-Char" from
573
* the given array of strings. Stops searching at the first marker "--".
575
* @param flag the character indicating the option.
576
* @param options the array of strings containing all the options.
577
* @return the position if found, or -1 otherwise
579
public static int getOptionPos(char flag, String[] options) {
580
return getOptionPos("" + flag, options);
584
* Gets the index of an option or flag indicated by a flag "-String" from
585
* the given array of strings. Stops searching at the first marker "--".
587
* @param flag the String indicating the option.
588
* @param options the array of strings containing all the options.
589
* @return the position if found, or -1 otherwise
591
public static int getOptionPos(String flag, String[] options) {
595
for (int i = 0; i < options.length; i++) {
596
if ((options[i].length() > 0) && (options[i].charAt(0) == '-')) {
597
// Check if it is a negative number
599
Double.valueOf(options[i]);
601
catch (NumberFormatException e) {
603
if (options[i].equals("-" + flag))
605
// did we reach "--"?
606
if (options[i].charAt(1) == '-')
616
* Quotes a string if it contains special characters.
618
* The following rules are applied:
620
* A character is backquoted version of it is one
621
* of <tt>" ' % \ \n \r \t</tt>.
623
* A string is enclosed within single quotes if a character has been
624
* backquoted using the previous rule above or contains
625
* <tt>{ }</tt> or is exactly equal to the strings
626
* <tt>, ? space or ""</tt> (empty string).
628
* A quoted question mark distinguishes it from the missing value which
629
* is represented as an unquoted question mark in arff files.
631
* @param string the string to be quoted
632
* @return the string (possibly quoted)
633
* @see #unquote(String)
635
public static /*@pure@*/ String quote(String string) {
636
boolean quote = false;
638
// backquote the following characters
639
if ((string.indexOf('\n') != -1) || (string.indexOf('\r') != -1) ||
640
(string.indexOf('\'') != -1) || (string.indexOf('"') != -1) ||
641
(string.indexOf('\\') != -1) ||
642
(string.indexOf('\t') != -1) || (string.indexOf('%') != -1)) {
643
string = backQuoteChars(string);
647
// Enclose the string in 's if the string contains a recently added
648
// backquote or contains one of the following characters.
649
if((quote == true) ||
650
(string.indexOf('{') != -1) || (string.indexOf('}') != -1) ||
651
(string.indexOf(',') != -1) || (string.equals("?")) ||
652
(string.indexOf(' ') != -1) || (string.equals(""))) {
653
string = ("'".concat(string)).concat("'");
660
* unquotes are previously quoted string (but only if necessary), i.e., it
661
* removes the single quotes around it. Inverse to quote(String).
663
* @param string the string to process
664
* @return the unquoted string
665
* @see #quote(String)
667
public static String unquote(String string) {
668
if (string.startsWith("'") && string.endsWith("'")) {
669
string = string.substring(1, string.length() - 1);
671
if ((string.indexOf("\\n") != -1) || (string.indexOf("\\r") != -1) ||
672
(string.indexOf("\\'") != -1) || (string.indexOf("\\\"") != -1) ||
673
(string.indexOf("\\\\") != -1) ||
674
(string.indexOf("\\t") != -1) || (string.indexOf("\\%") != -1)) {
675
string = unbackQuoteChars(string);
683
* Converts carriage returns and new lines in a string into \r and \n.
684
* Backquotes the following characters: ` " \ \t and %
686
* @param string the string
687
* @return the converted string
688
* @see #unbackQuoteChars(String)
690
public static /*@pure@*/ String backQuoteChars(String string) {
693
StringBuffer newStringBuffer;
695
// replace each of the following characters with the backquoted version
696
char charsFind[] = {'\\', '\'', '\t', '\n', '\r', '"', '%'};
697
String charsReplace[] = {"\\\\", "\\'", "\\t", "\\n", "\\r", "\\\"", "\\%"};
698
for (int i = 0; i < charsFind.length; i++) {
699
if (string.indexOf(charsFind[i]) != -1 ) {
700
newStringBuffer = new StringBuffer();
701
while ((index = string.indexOf(charsFind[i])) != -1) {
703
newStringBuffer.append(string.substring(0, index));
705
newStringBuffer.append(charsReplace[i]);
706
if ((index + 1) < string.length()) {
707
string = string.substring(index + 1);
712
newStringBuffer.append(string);
713
string = newStringBuffer.toString();
721
* Converts carriage returns and new lines in a string into \r and \n.
723
* @param string the string
724
* @return the converted string
726
public static String convertNewLines(String string) {
730
StringBuffer newStringBuffer = new StringBuffer();
731
while ((index = string.indexOf('\n')) != -1) {
733
newStringBuffer.append(string.substring(0, index));
735
newStringBuffer.append('\\');
736
newStringBuffer.append('n');
737
if ((index + 1) < string.length()) {
738
string = string.substring(index + 1);
743
newStringBuffer.append(string);
744
string = newStringBuffer.toString();
747
newStringBuffer = new StringBuffer();
748
while ((index = string.indexOf('\r')) != -1) {
750
newStringBuffer.append(string.substring(0, index));
752
newStringBuffer.append('\\');
753
newStringBuffer.append('r');
754
if ((index + 1) < string.length()){
755
string = string.substring(index + 1);
760
newStringBuffer.append(string);
761
return newStringBuffer.toString();
765
* Reverts \r and \n in a string into carriage returns and new lines.
767
* @param string the string
768
* @return the converted string
770
public static String revertNewLines(String string) {
774
StringBuffer newStringBuffer = new StringBuffer();
775
while ((index = string.indexOf("\\n")) != -1) {
777
newStringBuffer.append(string.substring(0, index));
779
newStringBuffer.append('\n');
780
if ((index + 2) < string.length()) {
781
string = string.substring(index + 2);
786
newStringBuffer.append(string);
787
string = newStringBuffer.toString();
790
newStringBuffer = new StringBuffer();
791
while ((index = string.indexOf("\\r")) != -1) {
793
newStringBuffer.append(string.substring(0, index));
795
newStringBuffer.append('\r');
796
if ((index + 2) < string.length()){
797
string = string.substring(index + 2);
802
newStringBuffer.append(string);
804
return newStringBuffer.toString();
808
* Returns the secondary set of options (if any) contained in
809
* the supplied options array. The secondary set is defined to
810
* be any options after the first "--". These options are removed from
811
* the original options array.
813
* @param options the input array of options
814
* @return the array of secondary options
816
public static String[] partitionOptions(String[] options) {
818
for (int i = 0; i < options.length; i++) {
819
if (options[i].equals("--")) {
821
String[] result = new String [options.length - i];
822
for (int j = i; j < options.length; j++) {
823
result[j - i] = options[j];
829
return new String [0];
833
* The inverse operation of backQuoteChars().
834
* Converts back-quoted carriage returns and new lines in a string
835
* to the corresponding character ('\r' and '\n').
836
* Also "un"-back-quotes the following characters: ` " \ \t and %
838
* @param string the string
839
* @return the converted string
840
* @see #backQuoteChars(String)
842
public static String unbackQuoteChars(String string) {
845
StringBuffer newStringBuffer;
847
// replace each of the following characters with the backquoted version
848
String charsFind[] = {"\\\\", "\\'", "\\t", "\\n", "\\r", "\\\"", "\\%"};
849
char charsReplace[] = {'\\', '\'', '\t', '\n', '\r', '"', '%'};
850
int pos[] = new int[charsFind.length];
853
String str = new String(string);
854
newStringBuffer = new StringBuffer();
855
while (str.length() > 0) {
856
// get positions and closest character to replace
857
curPos = str.length();
859
for (int i = 0; i < pos.length; i++) {
860
pos[i] = str.indexOf(charsFind[i]);
861
if ( (pos[i] > -1) && (pos[i] < curPos) ) {
867
// replace character if found, otherwise finished
869
newStringBuffer.append(str);
873
newStringBuffer.append(str.substring(0, pos[index]));
874
newStringBuffer.append(charsReplace[index]);
875
str = str.substring(pos[index] + charsFind[index].length());
879
return newStringBuffer.toString();
883
* Split up a string containing options into an array of strings,
884
* one for each option.
886
* @param quotedOptionString the string containing the options
887
* @return the array of options
888
* @throws Exception in case of an unterminated string, unknown character or
891
public static String[] splitOptions(String quotedOptionString) throws Exception{
893
FastVector optionsVec = new FastVector();
894
String str = new String(quotedOptionString);
901
while ((i < str.length()) && (Character.isWhitespace(str.charAt(i)))) i++;
902
str = str.substring(i);
904
//stop when str is empty
905
if (str.length() == 0) break;
907
//if str start with a double quote
908
if (str.charAt(0) == '"'){
910
//find the first not anti-slached double quote
912
while(i < str.length()){
913
if (str.charAt(i) == str.charAt(0)) break;
914
if (str.charAt(i) == '\\'){
916
if (i >= str.length())
917
throw new Exception("String should not finish with \\");
921
if (i >= str.length()) throw new Exception("Quote parse error.");
923
//add the founded string to the option vector (without quotes)
924
String optStr = str.substring(1,i);
925
optStr = unbackQuoteChars(optStr);
926
optionsVec.addElement(optStr);
927
str = str.substring(i+1);
929
//find first whiteSpace
931
while((i < str.length()) && (!Character.isWhitespace(str.charAt(i)))) i++;
933
//add the founded string to the option vector
934
String optStr = str.substring(0,i);
935
optionsVec.addElement(optStr);
936
str = str.substring(i);
940
//convert optionsVec to an array of String
941
String[] options = new String[optionsVec.size()];
942
for (i = 0; i < optionsVec.size(); i++) {
943
options[i] = (String)optionsVec.elementAt(i);
949
* Joins all the options in an option array into a single string,
950
* as might be used on the command line.
952
* @param optionArray the array of options
953
* @return the string containing all options.
955
public static String joinOptions(String[] optionArray) {
957
String optionString = "";
958
for (int i = 0; i < optionArray.length; i++) {
959
if (optionArray[i].equals("")) {
962
boolean escape = false;
963
for (int n = 0; n < optionArray[i].length(); n++) {
964
if (Character.isWhitespace(optionArray[i].charAt(n))) {
970
optionString += '"' + backQuoteChars(optionArray[i]) + '"';
972
optionString += optionArray[i];
976
return optionString.trim();
980
* Creates a new instance of an object given it's class name and
981
* (optional) arguments to pass to it's setOptions method. If the
982
* object implements OptionHandler and the options parameter is
983
* non-null, the object will have it's options set. Example use:<p>
986
* String classifierName = Utils.getOption('W', options);
987
* Classifier c = (Classifier)Utils.forName(Classifier.class,
993
* @param classType the class that the instantiated object should
994
* be assignable to -- an exception is thrown if this is not the case
995
* @param className the fully qualified class name of the object
996
* @param options an array of options suitable for passing to setOptions. May
997
* be null. Any options accepted by the object will be removed from the
999
* @return the newly created object, ready for use.
1000
* @exception Exception if the class name is invalid, or if the
1001
* class is not assignable to the desired class type, or the options
1002
* supplied are not acceptable to the object
1004
public static Object forName(Class classType,
1006
String[] options) throws Exception {
1010
c = Class.forName(className);
1011
} catch (Exception ex) {
1012
throw new Exception("Can't find class called: " + className);
1014
if (!classType.isAssignableFrom(c)) {
1015
throw new Exception(classType.getName() + " is not assignable from "
1018
Object o = c.newInstance();
1019
if ((o instanceof OptionHandler)
1020
&& (options != null)) {
1021
((OptionHandler)o).setOptions(options);
1022
Utils.checkForRemainingOptions(options);
1028
* Computes entropy for an array of integers.
1030
* @param counts array of counts
1031
* @return - a log2 a - b log2 b - c log2 c + (a+b+c) log2 (a+b+c)
1032
* when given array [a b c]
1034
public static /*@pure@*/ double info(int counts[]) {
1038
for (int j = 0; j < counts.length; j++) {
1039
x -= xlogx(counts[j]);
1042
return x + xlogx(total);
1046
* Tests if a is smaller or equal to b.
1051
public static /*@pure@*/ boolean smOrEq(double a,double b) {
1053
return (a-b < SMALL);
1057
* Tests if a is greater or equal to b.
1062
public static /*@pure@*/ boolean grOrEq(double a,double b) {
1064
return (b-a < SMALL);
1068
* Tests if a is smaller than b.
1073
public static /*@pure@*/ boolean sm(double a,double b) {
1075
return (b-a > SMALL);
1079
* Tests if a is greater than b.
1084
public static /*@pure@*/ boolean gr(double a,double b) {
1086
return (a-b > SMALL);
1090
* Returns the kth-smallest value in the array.
1092
* @param array the array of integers
1093
* @param k the value of k
1094
* @return the kth-smallest value
1096
public static double kthSmallestValue(int[] array, int k) {
1098
int[] index = new int[array.length];
1100
for (int i = 0; i < index.length; i++) {
1104
return array[index[select(array, index, 0, array.length - 1, k)]];
1108
* Returns the kth-smallest value in the array
1110
* @param array the array of double
1111
* @param k the value of k
1112
* @return the kth-smallest value
1114
public static double kthSmallestValue(double[] array, int k) {
1116
int[] index = new int[array.length];
1118
for (int i = 0; i < index.length; i++) {
1122
return array[index[select(array, index, 0, array.length - 1, k)]];
1126
* Returns the logarithm of a for base 2.
1129
* @return the logarithm for base 2
1131
public static /*@pure@*/ double log2(double a) {
1133
return Math.log(a) / log2;
1137
* Returns index of maximum element in a given
1138
* array of doubles. First maximum is returned.
1140
* @param doubles the array of doubles
1141
* @return the index of the maximum element
1143
public static /*@pure@*/ int maxIndex(double[] doubles) {
1148
for (int i = 0; i < doubles.length; i++) {
1149
if ((i == 0) || (doubles[i] > maximum)) {
1151
maximum = doubles[i];
1159
* Returns index of maximum element in a given
1160
* array of integers. First maximum is returned.
1162
* @param ints the array of integers
1163
* @return the index of the maximum element
1165
public static /*@pure@*/ int maxIndex(int[] ints) {
1170
for (int i = 0; i < ints.length; i++) {
1171
if ((i == 0) || (ints[i] > maximum)) {
1181
* Computes the mean for an array of doubles.
1183
* @param vector the array
1186
public static /*@pure@*/ double mean(double[] vector) {
1190
if (vector.length == 0) {
1193
for (int i = 0; i < vector.length; i++) {
1196
return sum / (double) vector.length;
1200
* Returns index of minimum element in a given
1201
* array of integers. First minimum is returned.
1203
* @param ints the array of integers
1204
* @return the index of the minimum element
1206
public static /*@pure@*/ int minIndex(int[] ints) {
1211
for (int i = 0; i < ints.length; i++) {
1212
if ((i == 0) || (ints[i] < minimum)) {
1222
* Returns index of minimum element in a given
1223
* array of doubles. First minimum is returned.
1225
* @param doubles the array of doubles
1226
* @return the index of the minimum element
1228
public static /*@pure@*/ int minIndex(double[] doubles) {
1233
for (int i = 0; i < doubles.length; i++) {
1234
if ((i == 0) || (doubles[i] < minimum)) {
1236
minimum = doubles[i];
1244
* Normalizes the doubles in the array by their sum.
1246
* @param doubles the array of double
1247
* @exception IllegalArgumentException if sum is Zero or NaN
1249
public static void normalize(double[] doubles) {
1252
for (int i = 0; i < doubles.length; i++) {
1255
normalize(doubles, sum);
1259
* Normalizes the doubles in the array using the given value.
1261
* @param doubles the array of double
1262
* @param sum the value by which the doubles are to be normalized
1263
* @exception IllegalArgumentException if sum is zero or NaN
1265
public static void normalize(double[] doubles, double sum) {
1267
if (Double.isNaN(sum)) {
1268
throw new IllegalArgumentException("Can't normalize array. Sum is NaN.");
1271
// Maybe this should just be a return.
1272
throw new IllegalArgumentException("Can't normalize array. Sum is zero.");
1274
for (int i = 0; i < doubles.length; i++) {
1280
* Converts an array containing the natural logarithms of
1281
* probabilities stored in a vector back into probabilities.
1282
* The probabilities are assumed to sum to one.
1284
* @param a an array holding the natural logarithms of the probabilities
1285
* @return the converted array
1287
public static double[] logs2probs(double[] a) {
1289
double max = a[maxIndex(a)];
1292
double[] result = new double[a.length];
1293
for(int i = 0; i < a.length; i++) {
1294
result[i] = Math.exp(a[i] - max);
1298
normalize(result, sum);
1304
* Returns the log-odds for a given probabilitiy.
1306
* @param prob the probabilitiy
1308
* @return the log-odds after the probability has been mapped to
1309
* [Utils.SMALL, 1-Utils.SMALL]
1311
public static /*@pure@*/ double probToLogOdds(double prob) {
1313
if (gr(prob, 1) || (sm(prob, 0))) {
1314
throw new IllegalArgumentException("probToLogOdds: probability must " +
1315
"be in [0,1] "+prob);
1317
double p = SMALL + (1.0 - 2 * SMALL) * prob;
1318
return Math.log(p / (1 - p));
1322
* Rounds a double to the next nearest integer value. The JDK version
1323
* of it doesn't work properly.
1325
* @param value the double value
1326
* @return the resulting integer value
1328
public static /*@pure@*/ int round(double value) {
1330
int roundedValue = value > 0
1331
? (int)(value + 0.5)
1332
: -(int)(Math.abs(value) + 0.5);
1334
return roundedValue;
1338
* Rounds a double to the next nearest integer value in a probabilistic
1339
* fashion (e.g. 0.8 has a 20% chance of being rounded down to 0 and a
1340
* 80% chance of being rounded up to 1). In the limit, the average of
1341
* the rounded numbers generated by this procedure should converge to
1342
* the original double.
1344
* @param value the double value
1345
* @param rand the random number generator
1346
* @return the resulting integer value
1348
public static int probRound(double value, Random rand) {
1351
double lower = Math.floor(value);
1352
double prob = value - lower;
1353
if (rand.nextDouble() < prob) {
1354
return (int)lower + 1;
1359
double lower = Math.floor(Math.abs(value));
1360
double prob = Math.abs(value) - lower;
1361
if (rand.nextDouble() < prob) {
1362
return -((int)lower + 1);
1370
* Rounds a double to the given number of decimal places.
1372
* @param value the double value
1373
* @param afterDecimalPoint the number of digits after the decimal point
1374
* @return the double rounded to the given precision
1376
public static /*@pure@*/ double roundDouble(double value,int afterDecimalPoint) {
1378
double mask = Math.pow(10.0, (double)afterDecimalPoint);
1380
return (double)(Math.round(value * mask)) / mask;
1384
* Sorts a given array of integers in ascending order and returns an
1385
* array of integers with the positions of the elements of the original
1386
* array in the sorted array. The sort is stable. (Equal elements remain
1387
* in their original order.)
1389
* @param array this array is not changed by the method!
1390
* @return an array of integers with the positions in the sorted
1393
public static /*@pure@*/ int[] sort(int[] array) {
1395
int[] index = new int[array.length];
1396
int[] newIndex = new int[array.length];
1400
for (int i = 0; i < index.length; i++) {
1403
quickSort(array, index, 0, array.length - 1);
1407
while (i < index.length) {
1409
for (int j = i + 1; ((j < index.length)
1410
&& (array[index[i]] == array[index[j]]));
1415
helpIndex = new int[numEqual];
1416
for (int j = 0; j < numEqual; j++) {
1417
helpIndex[j] = i + j;
1419
quickSort(index, helpIndex, 0, numEqual - 1);
1420
for (int j = 0; j < numEqual; j++) {
1421
newIndex[i + j] = index[helpIndex[j]];
1425
newIndex[i] = index[i];
1433
* Sorts a given array of doubles in ascending order and returns an
1434
* array of integers with the positions of the elements of the
1435
* original array in the sorted array. NOTE THESE CHANGES: the sort
1436
* is no longer stable and it doesn't use safe floating-point
1437
* comparisons anymore. Occurrences of Double.NaN are treated as
1440
* @param array this array is not changed by the method!
1441
* @return an array of integers with the positions in the sorted
1444
public static /*@pure@*/ int[] sort(/*@non_null@*/ double[] array) {
1446
int[] index = new int[array.length];
1447
array = (double[])array.clone();
1448
for (int i = 0; i < index.length; i++) {
1450
if (Double.isNaN(array[i])) {
1451
array[i] = Double.MAX_VALUE;
1454
quickSort(array, index, 0, array.length - 1);
1459
* Sorts a given array of doubles in ascending order and returns an
1460
* array of integers with the positions of the elements of the original
1461
* array in the sorted array. The sort is stable (Equal elements remain
1462
* in their original order.) Occurrences of Double.NaN are treated as
1465
* @param array this array is not changed by the method!
1466
* @return an array of integers with the positions in the sorted
1469
public static /*@pure@*/ int[] stableSort(double[] array){
1471
int[] index = new int[array.length];
1472
int[] newIndex = new int[array.length];
1476
array = (double[])array.clone();
1477
for (int i = 0; i < index.length; i++) {
1479
if (Double.isNaN(array[i])) {
1480
array[i] = Double.MAX_VALUE;
1483
quickSort(array,index,0,array.length-1);
1488
while (i < index.length) {
1490
for (int j = i+1; ((j < index.length) && Utils.eq(array[index[i]],
1491
array[index[j]])); j++)
1494
helpIndex = new int[numEqual];
1495
for (int j = 0; j < numEqual; j++)
1497
quickSort(index, helpIndex, 0, numEqual-1);
1498
for (int j = 0; j < numEqual; j++)
1499
newIndex[i+j] = index[helpIndex[j]];
1502
newIndex[i] = index[i];
1511
* Computes the variance for an array of doubles.
1513
* @param vector the array
1514
* @return the variance
1516
public static /*@pure@*/ double variance(double[] vector) {
1518
double sum = 0, sumSquared = 0;
1520
if (vector.length <= 1) {
1523
for (int i = 0; i < vector.length; i++) {
1525
sumSquared += (vector[i] * vector[i]);
1527
double result = (sumSquared - (sum * sum / (double) vector.length)) /
1528
(double) (vector.length - 1);
1530
// We don't like negative variance
1539
* Computes the sum of the elements of an array of doubles.
1541
* @param doubles the array of double
1542
* @return the sum of the elements
1544
public static /*@pure@*/ double sum(double[] doubles) {
1548
for (int i = 0; i < doubles.length; i++) {
1555
* Computes the sum of the elements of an array of integers.
1557
* @param ints the array of integers
1558
* @return the sum of the elements
1560
public static /*@pure@*/ int sum(int[] ints) {
1564
for (int i = 0; i < ints.length; i++) {
1571
* Returns c*log2(c) for a given integer value c.
1573
* @param c an integer value
1574
* @return c*log2(c) (but is careful to return 0 if c is 0)
1576
public static /*@pure@*/ double xlogx(int c) {
1581
return c * Utils.log2((double) c);
1585
* Partitions the instances around a pivot. Used by quicksort and
1588
* @param array the array of doubles to be sorted
1589
* @param index the index into the array of doubles
1590
* @param l the first index of the subset
1591
* @param r the last index of the subset
1593
* @return the index of the middle element
1595
private static int partition(double[] array, int[] index, int l, int r) {
1597
double pivot = array[index[(l + r) / 2]];
1601
while ((array[index[l]] < pivot) && (l < r)) {
1604
while ((array[index[r]] > pivot) && (l < r)) {
1609
index[l] = index[r];
1615
if ((l == r) && (array[index[r]] > pivot)) {
1623
* Partitions the instances around a pivot. Used by quicksort and
1626
* @param array the array of integers to be sorted
1627
* @param index the index into the array of integers
1628
* @param l the first index of the subset
1629
* @param r the last index of the subset
1631
* @return the index of the middle element
1633
private static int partition(int[] array, int[] index, int l, int r) {
1635
double pivot = array[index[(l + r) / 2]];
1639
while ((array[index[l]] < pivot) && (l < r)) {
1642
while ((array[index[r]] > pivot) && (l < r)) {
1647
index[l] = index[r];
1653
if ((l == r) && (array[index[r]] > pivot)) {
1661
* Implements quicksort according to Manber's "Introduction to
1664
* @param array the array of doubles to be sorted
1665
* @param index the index into the array of doubles
1666
* @param left the first index of the subset to be sorted
1667
* @param right the last index of the subset to be sorted
1669
//@ requires 0 <= first && first <= right && right < array.length;
1670
//@ requires (\forall int i; 0 <= i && i < index.length; 0 <= index[i] && index[i] < array.length);
1671
//@ requires array != index;
1672
// assignable index;
1673
private static void quickSort(/*@non_null@*/ double[] array, /*@non_null@*/ int[] index,
1674
int left, int right) {
1677
int middle = partition(array, index, left, right);
1678
quickSort(array, index, left, middle);
1679
quickSort(array, index, middle + 1, right);
1684
* Implements quicksort according to Manber's "Introduction to
1687
* @param array the array of integers to be sorted
1688
* @param index the index into the array of integers
1689
* @param left the first index of the subset to be sorted
1690
* @param right the last index of the subset to be sorted
1692
//@ requires 0 <= first && first <= right && right < array.length;
1693
//@ requires (\forall int i; 0 <= i && i < index.length; 0 <= index[i] && index[i] < array.length);
1694
//@ requires array != index;
1695
// assignable index;
1696
private static void quickSort(/*@non_null@*/ int[] array, /*@non_null@*/ int[] index,
1697
int left, int right) {
1700
int middle = partition(array, index, left, right);
1701
quickSort(array, index, left, middle);
1702
quickSort(array, index, middle + 1, right);
1707
* Implements computation of the kth-smallest element according
1708
* to Manber's "Introduction to Algorithms".
1710
* @param array the array of double
1711
* @param index the index into the array of doubles
1712
* @param left the first index of the subset
1713
* @param right the last index of the subset
1714
* @param k the value of k
1716
* @return the index of the kth-smallest element
1718
//@ requires 0 <= first && first <= right && right < array.length;
1719
private static int select(/*@non_null@*/ double[] array, /*@non_null@*/ int[] index,
1720
int left, int right, int k) {
1722
if (left == right) {
1725
int middle = partition(array, index, left, right);
1726
if ((middle - left + 1) >= k) {
1727
return select(array, index, left, middle, k);
1729
return select(array, index, middle + 1, right, k - (middle - left + 1));
1735
* Implements computation of the kth-smallest element according
1736
* to Manber's "Introduction to Algorithms".
1738
* @param array the array of integers
1739
* @param index the index into the array of integers
1740
* @param left the first index of the subset
1741
* @param right the last index of the subset
1742
* @param k the value of k
1744
* @return the index of the kth-smallest element
1746
//@ requires 0 <= first && first <= right && right < array.length;
1747
private static int select(/*@non_null@*/ int[] array, /*@non_null@*/ int[] index,
1748
int left, int right, int k) {
1750
if (left == right) {
1753
int middle = partition(array, index, left, right);
1754
if ((middle - left + 1) >= k) {
1755
return select(array, index, left, middle, k);
1757
return select(array, index, middle + 1, right, k - (middle - left + 1));
1763
* Main method for testing this class.
1765
* @param ops some dummy options
1767
public static void main(String[] ops) {
1769
double[] doublesWithNaN = {4.5, 6.7, Double.NaN, 3.4, 4.8, 1.2, 3.4};
1770
double[] doubles = {4.5, 6.7, 6.7, 3.4, 4.8, 1.2, 3.4, 6.7, 6.7, 3.4};
1771
int[] ints = {12, 6, 2, 18, 16, 6, 7, 5, 18, 18, 17};
1776
System.out.println("First option split up:");
1777
if (ops.length > 0) {
1778
String[] firstOptionSplitUp = Utils.splitOptions(ops[0]);
1779
for (int i = 0; i < firstOptionSplitUp.length; i ++) {
1780
System.out.println(firstOptionSplitUp[i]);
1783
System.out.println("Partitioned options: ");
1784
String[] partitionedOptions = Utils.partitionOptions(ops);
1785
for (int i = 0; i < partitionedOptions.length; i++) {
1786
System.out.println(partitionedOptions[i]);
1788
System.out.println("Get position of flag -f: " + Utils.getOptionPos('f', ops));
1789
System.out.println("Get flag -f: " + Utils.getFlag('f', ops));
1790
System.out.println("Get position of option -o: " + Utils.getOptionPos('o', ops));
1791
System.out.println("Get option -o: " + Utils.getOption('o', ops));
1792
System.out.println("Checking for remaining options... ");
1793
Utils.checkForRemainingOptions(ops);
1796
System.out.println("Original array with NaN (doubles): ");
1797
for (int i = 0; i < doublesWithNaN.length; i++) {
1798
System.out.print(doublesWithNaN[i] + " ");
1800
System.out.println();
1801
System.out.println("Original array (doubles): ");
1802
for (int i = 0; i < doubles.length; i++) {
1803
System.out.print(doubles[i] + " ");
1805
System.out.println();
1806
System.out.println("Original array (ints): ");
1807
for (int i = 0; i < ints.length; i++) {
1808
System.out.print(ints[i] + " ");
1810
System.out.println();
1811
System.out.println("Correlation: " + Utils.correlation(doubles, doubles,
1813
System.out.println("Mean: " + Utils.mean(doubles));
1814
System.out.println("Variance: " + Utils.variance(doubles));
1815
System.out.println("Sum (doubles): " + Utils.sum(doubles));
1816
System.out.println("Sum (ints): " + Utils.sum(ints));
1817
System.out.println("Max index (doubles): " + Utils.maxIndex(doubles));
1818
System.out.println("Max index (ints): " + Utils.maxIndex(ints));
1819
System.out.println("Min index (doubles): " + Utils.minIndex(doubles));
1820
System.out.println("Min index (ints): " + Utils.minIndex(ints));
1821
System.out.println("Median (doubles): " +
1822
Utils.kthSmallestValue(doubles, doubles.length / 2));
1823
System.out.println("Median (ints): " +
1824
Utils.kthSmallestValue(ints, ints.length / 2));
1826
// Sorting and normalizing
1827
System.out.println("Sorted array with NaN (doubles): ");
1828
int[] sorted = Utils.sort(doublesWithNaN);
1829
for (int i = 0; i < doublesWithNaN.length; i++) {
1830
System.out.print(doublesWithNaN[sorted[i]] + " ");
1832
System.out.println();
1833
System.out.println("Sorted array (doubles): ");
1834
sorted = Utils.sort(doubles);
1835
for (int i = 0; i < doubles.length; i++) {
1836
System.out.print(doubles[sorted[i]] + " ");
1838
System.out.println();
1839
System.out.println("Sorted array (ints): ");
1840
sorted = Utils.sort(ints);
1841
for (int i = 0; i < ints.length; i++) {
1842
System.out.print(ints[sorted[i]] + " ");
1844
System.out.println();
1845
System.out.println("Indices from stable sort (doubles): ");
1846
sorted = Utils.stableSort(doubles);
1847
for (int i = 0; i < doubles.length; i++) {
1848
System.out.print(sorted[i] + " ");
1850
System.out.println();
1851
System.out.println("Indices from sort (ints): ");
1852
sorted = Utils.sort(ints);
1853
for (int i = 0; i < ints.length; i++) {
1854
System.out.print(sorted[i] + " ");
1856
System.out.println();
1857
System.out.println("Normalized array (doubles): ");
1858
Utils.normalize(doubles);
1859
for (int i = 0; i < doubles.length; i++) {
1860
System.out.print(doubles[i] + " ");
1862
System.out.println();
1863
System.out.println("Normalized again (doubles): ");
1864
Utils.normalize(doubles, Utils.sum(doubles));
1865
for (int i = 0; i < doubles.length; i++) {
1866
System.out.print(doubles[i] + " ");
1868
System.out.println();
1871
System.out.println("-4.58: " + Utils.doubleToString(-4.57826535, 2));
1872
System.out.println("-6.78: " + Utils.doubleToString(-6.78214234, 6,2));
1875
System.out.println("5.70001 == 5.7 ? " + Utils.eq(5.70001, 5.7));
1876
System.out.println("5.70001 > 5.7 ? " + Utils.gr(5.70001, 5.7));
1877
System.out.println("5.70001 >= 5.7 ? " + Utils.grOrEq(5.70001, 5.7));
1878
System.out.println("5.7 < 5.70001 ? " + Utils.sm(5.7, 5.70001));
1879
System.out.println("5.7 <= 5.70001 ? " + Utils.smOrEq(5.7, 5.70001));
1882
System.out.println("Info (ints): " + Utils.info(ints));
1883
System.out.println("log2(4.6): " + Utils.log2(4.6));
1884
System.out.println("5 * log(5): " + Utils.xlogx(5));
1885
System.out.println("5.5 rounded: " + Utils.round(5.5));
1886
System.out.println("5.55555 rounded to 2 decimal places: " +
1887
Utils.roundDouble(5.55555, 2));
1890
System.out.println("Array-Dimensions of 'new int[][]': " + Utils.getArrayDimensions(new int[][]{}));
1891
System.out.println("Array-Dimensions of 'new int[][]{{1,2,3},{4,5,6}}': " + Utils.getArrayDimensions(new int[][]{{1,2,3},{4,5,6}}));
1892
String[][][] s = new String[3][4][];
1893
System.out.println("Array-Dimensions of 'new String[3][4][]': " + Utils.getArrayDimensions(s));
1894
} catch (Exception e) {
1895
e.printStackTrace();