/* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* * Utils.java * Copyright (C) 1999-2012 University of Waikato, Hamilton, New Zealand * */ package weka.core; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.FileWriter; import java.lang.reflect.Array; import java.net.URL; import java.text.BreakIterator; import java.util.Enumeration; import java.util.Properties; import java.util.Random; import java.util.Vector; /** * Class implementing some simple utility methods. * * @author Eibe Frank * @author Yong Wang * @author Len Trigg * @author Julien Prados * @version $Revision: 9736 $ */ public final class Utils implements RevisionHandler { /** The natural logarithm of 2. */ public static double log2 = Math.log(2); /** The small deviation allowed in double comparisons. */ public static double SMALL = 1e-6; /** * Tests if the given value codes "missing". * * @param val the value to be tested * @return true if val codes "missing" */ public static boolean isMissingValue(double val) { return Double.isNaN(val); } /** * Returns the value used to code a missing value. Note that * equality tests on this value will always return false, so use * isMissingValue(double val) for testing.. * * @return the value used as missing value. */ public static double missingValue() { return Double.NaN; } /** * Casting an object without "unchecked" compile-time warnings. * Use only when absolutely necessary (e.g. when using clone()). */ @SuppressWarnings("unchecked") public static <T> T cast(Object x) { return (T) x; } /** * Reads properties that inherit from three locations. Properties * are first defined in the system resource location (i.e. in the * CLASSPATH). These default properties must exist. Properties optionally * defined in the user properties location (WekaPackageManager.PROPERTIES_DIR) * override default settings. Properties defined in the current directory (optional) * override all these settings. * * @param resourceName the location of the resource that should be * loaded. e.g.: "weka/core/Utils.props". (The use of hardcoded * forward slashes here is OK - see * jdk1.1/docs/guide/misc/resources.html) This routine will also * look for the file (in this case) "Utils.props" in the users home * directory and the current directory. * @return the Properties * @exception Exception if no default properties are defined, or if * an error occurs reading the properties files. */ public static Properties readProperties(String resourceName) throws Exception { Properties defaultProps = new Properties(); try { // Apparently hardcoded slashes are OK here // jdk1.1/docs/guide/misc/resources.html Utils utils = new Utils(); Enumeration<URL> urls = utils.getClass().getClassLoader().getResources(resourceName); boolean first = true; while (urls.hasMoreElements()) { URL url = urls.nextElement(); if (first) { defaultProps.load(url.openStream()); first = false; } else { Properties props = new Properties(defaultProps); props.load(url.openStream()); defaultProps = props; } } } catch (Exception ex) { System.err.println("Warning, unable to load properties file(s) from " +"system resource (Utils.java): " + resourceName); } // Hardcoded slash is OK here // eg: see jdk1.1/docs/guide/misc/resources.html int slInd = resourceName.lastIndexOf('/'); if (slInd != -1) { resourceName = resourceName.substring(slInd + 1); } /* Allow a properties file in the WekaPackageManager.PROPERTIES_DIR to override Properties userProps = new Properties(defaultProps); if (!WekaPackageManager.PROPERTIES_DIR.exists()) { WekaPackageManager.PROPERTIES_DIR.mkdir(); } File propFile = new File(WekaPackageManager.PROPERTIES_DIR.toString() + File.separator + resourceName); if (propFile.exists()) { try { userProps.load(new FileInputStream(propFile)); } catch (Exception ex) { throw new Exception("Problem reading user properties: " + propFile); } } // Allow a properties file in the current directory to override Properties localProps = new Properties(userProps); propFile = new File(resourceName); if (propFile.exists()) { try { localProps.load(new FileInputStream(propFile)); } catch (Exception ex) { throw new Exception("Problem reading local properties: " + propFile); } } */ return defaultProps; } /** * Returns the correlation coefficient of two double vectors. * * @param y1 double vector 1 * @param y2 double vector 2 * @param n the length of two double vectors * @return the correlation coefficient */ public static final double correlation(double y1[],double y2[],int n) { int i; double av1 = 0.0, av2 = 0.0, y11 = 0.0, y22 = 0.0, y12 = 0.0, c; if (n <= 1) { return 1.0; } for (i = 0; i < n; i++) { av1 += y1[i]; av2 += y2[i]; } av1 /= (double) n; av2 /= (double) n; for (i = 0; i < n; i++) { y11 += (y1[i] - av1) * (y1[i] - av1); y22 += (y2[i] - av2) * (y2[i] - av2); y12 += (y1[i] - av1) * (y2[i] - av2); } if (y11 * y22 == 0.0) { c=1.0; } else { c = y12 / Math.sqrt(Math.abs(y11 * y22)); } return c; } /** * Removes all occurrences of a string from another string. * * @param inString the string to remove substrings from. * @param substring the substring to remove. * @return the input string with occurrences of substring removed. */ public static String removeSubstring(String inString, String substring) { StringBuffer result = new StringBuffer(); int oldLoc = 0, loc = 0; while ((loc = inString.indexOf(substring, oldLoc))!= -1) { result.append(inString.substring(oldLoc, loc)); oldLoc = loc + substring.length(); } result.append(inString.substring(oldLoc)); return result.toString(); } /** * Replaces with a new string, all occurrences of a string from * another string. * * @param inString the string to replace substrings in. * @param subString the substring to replace. * @param replaceString the replacement substring * @return the input string with occurrences of substring replaced. */ public static String replaceSubstring(String inString, String subString, String replaceString) { StringBuffer result = new StringBuffer(); int oldLoc = 0, loc = 0; while ((loc = inString.indexOf(subString, oldLoc))!= -1) { result.append(inString.substring(oldLoc, loc)); result.append(replaceString); oldLoc = loc + subString.length(); } result.append(inString.substring(oldLoc)); return result.toString(); } /** * Pads a string to a specified length, inserting spaces on the left * as required. If the string is too long, characters are removed (from * the right). * * @param inString the input string * @param length the desired length of the output string * @return the output string */ public static String padLeft(String inString, int length) { return fixStringLength(inString, length, false); } /** * Pads a string to a specified length, inserting spaces on the right * as required. If the string is too long, characters are removed (from * the right). * * @param inString the input string * @param length the desired length of the output string * @return the output string */ public static String padRight(String inString, int length) { return fixStringLength(inString, length, true); } /** * Pads a string to a specified length, inserting spaces as * required. If the string is too long, characters are removed (from * the right). * * @param inString the input string * @param length the desired length of the output string * @param right true if inserted spaces should be added to the right * @return the output string */ private static /*@pure@*/ String fixStringLength(String inString, int length, boolean right) { if (inString.length() < length) { while (inString.length() < length) { inString = (right ? inString.concat(" ") : " ".concat(inString)); } } else if (inString.length() > length) { inString = inString.substring(0, length); } return inString; } /** * Rounds a double and converts it into String. * * @param value the double value * @param afterDecimalPoint the (maximum) number of digits permitted * after the decimal point * @return the double as a formatted string */ public static /*@pure@*/ String doubleToString(double value, int afterDecimalPoint) { StringBuffer stringBuffer; double temp; int dotPosition; long precisionValue; temp = value * Math.pow(10.0, afterDecimalPoint); if (Math.abs(temp) < Long.MAX_VALUE) { precisionValue = (temp > 0) ? (long)(temp + 0.5) : -(long)(Math.abs(temp) + 0.5); if (precisionValue == 0) { stringBuffer = new StringBuffer(String.valueOf(0)); } else { stringBuffer = new StringBuffer(String.valueOf(precisionValue)); } if (afterDecimalPoint == 0) { return stringBuffer.toString(); } dotPosition = stringBuffer.length() - afterDecimalPoint; while (((precisionValue < 0) && (dotPosition < 1)) || (dotPosition < 0)) { if (precisionValue < 0) { stringBuffer.insert(1, '0'); } else { stringBuffer.insert(0, '0'); } dotPosition++; } stringBuffer.insert(dotPosition, '.'); if ((precisionValue < 0) && (stringBuffer.charAt(1) == '.')) { stringBuffer.insert(1, '0'); } else if (stringBuffer.charAt(0) == '.') { stringBuffer.insert(0, '0'); } int currentPos = stringBuffer.length() - 1; while ((currentPos > dotPosition) && (stringBuffer.charAt(currentPos) == '0')) { stringBuffer.setCharAt(currentPos--, ' '); } if (stringBuffer.charAt(currentPos) == '.') { stringBuffer.setCharAt(currentPos, ' '); } return stringBuffer.toString().trim(); } return new String("" + value); } /** * Rounds a double and converts it into a formatted decimal-justified String. * Trailing 0's are replaced with spaces. * * @param value the double value * @param width the width of the string * @param afterDecimalPoint the number of digits after the decimal point * @return the double as a formatted string */ public static /*@pure@*/ String doubleToString(double value, int width, int afterDecimalPoint) { String tempString = doubleToString(value, afterDecimalPoint); char[] result; int dotPosition; if ((afterDecimalPoint >= width) || (tempString.indexOf('E') != -1)) { // Protects sci notation return tempString; } // Initialize result result = new char[width]; for (int i = 0; i < result.length; i++) { result[i] = ' '; } if (afterDecimalPoint > 0) { // Get position of decimal point and insert decimal point dotPosition = tempString.indexOf('.'); if (dotPosition == -1) { dotPosition = tempString.length(); } else { result[width - afterDecimalPoint - 1] = '.'; } } else { dotPosition = tempString.length(); } int offset = width - afterDecimalPoint - dotPosition; if (afterDecimalPoint > 0) { offset--; } // Not enough room to decimal align within the supplied width if (offset < 0) { return tempString; } // Copy characters before decimal point for (int i = 0; i < dotPosition; i++) { result[offset + i] = tempString.charAt(i); } // Copy characters after decimal point for (int i = dotPosition + 1; i < tempString.length(); i++) { result[offset + i] = tempString.charAt(i); } return new String(result); } /** * Returns the basic class of an array class (handles multi-dimensional * arrays). * @param c the array to inspect * @return the class of the innermost elements */ public static Class getArrayClass(Class c) { if (c.getComponentType().isArray()) return getArrayClass(c.getComponentType()); else return c.getComponentType(); } /** * Returns the dimensions of the given array. Even though the * parameter is of type "Object" one can hand over primitve arrays, e.g. * int[3] or double[2][4]. * * @param array the array to determine the dimensions for * @return the dimensions of the array */ public static int getArrayDimensions(Class array) { if (array.getComponentType().isArray()) return 1 + getArrayDimensions(array.getComponentType()); else return 1; } /** * Returns the dimensions of the given array. Even though the * parameter is of type "Object" one can hand over primitve arrays, e.g. * int[3] or double[2][4]. * * @param array the array to determine the dimensions for * @return the dimensions of the array */ public static int getArrayDimensions(Object array) { return getArrayDimensions(array.getClass()); } /** * Returns the given Array in a string representation. Even though the * parameter is of type "Object" one can hand over primitve arrays, e.g. * int[3] or double[2][4]. * * @param array the array to return in a string representation * @return the array as string */ public static String arrayToString(Object array) { String result; int dimensions; int i; result = ""; dimensions = getArrayDimensions(array); if (dimensions == 0) { result = "null"; } else if (dimensions == 1) { for (i = 0; i < Array.getLength(array); i++) { if (i > 0) result += ","; if (Array.get(array, i) == null) result += "null"; else result += Array.get(array, i).toString(); } } else { for (i = 0; i < Array.getLength(array); i++) { if (i > 0) result += ","; result += "[" + arrayToString(Array.get(array, i)) + "]"; } } return result; } /** * Tests if a is equal to b. * * @param a a double * @param b a double */ public static /*@pure@*/ boolean eq(double a, double b){ return (a == b) || ((a - b < SMALL) && (b - a < SMALL)); } /** * Checks if the given array contains any non-empty options. * * @param options an array of strings * @exception Exception if there are any non-empty options */ public static void checkForRemainingOptions(String[] options) throws Exception { int illegalOptionsFound = 0; StringBuffer text = new StringBuffer(); if (options == null) { return; } for (int i = 0; i < options.length; i++) { if (options[i].length() > 0) { illegalOptionsFound++; text.append(options[i] + ' '); } } if (illegalOptionsFound > 0) { throw new Exception("Illegal options: " + text); } } /** * Checks if the given array contains the flag "-Char". Stops * searching at the first marker "--". If the flag is found, * it is replaced with the empty string. * * @param flag the character indicating the flag. * @param options the array of strings containing all the options. * @return true if the flag was found * @exception Exception if an illegal option was found */ public static boolean getFlag(char flag, String[] options) throws Exception { return getFlag("" + flag, options); } /** * Checks if the given array contains the flag "-String". Stops * searching at the first marker "--". If the flag is found, * it is replaced with the empty string. * * @param flag the String indicating the flag. * @param options the array of strings containing all the options. * @return true if the flag was found * @exception Exception if an illegal option was found */ public static boolean getFlag(String flag, String[] options) throws Exception { int pos = getOptionPos(flag, options); if (pos > -1) options[pos] = ""; return (pos > -1); } /** * Gets an option indicated by a flag "-Char" from the given array * of strings. Stops searching at the first marker "--". Replaces * flag and option with empty strings. * * @param flag the character indicating the option. * @param options the array of strings containing all the options. * @return the indicated option or an empty string * @exception Exception if the option indicated by the flag can't be found */ public static /*@non_null@*/ String getOption(char flag, String[] options) throws Exception { return getOption("" + flag, options); } /** * Gets an option indicated by a flag "-String" from the given array * of strings. Stops searching at the first marker "--". Replaces * flag and option with empty strings. * * @param flag the String indicating the option. * @param options the array of strings containing all the options. * @return the indicated option or an empty string * @exception Exception if the option indicated by the flag can't be found */ public static /*@non_null@*/ String getOption(String flag, String[] options) throws Exception { String newString; int i = getOptionPos(flag, options); if (i > -1) { if (options[i].equals("-" + flag)) { if (i + 1 == options.length) { throw new Exception("No value given for -" + flag + " option."); } options[i] = ""; newString = new String(options[i + 1]); options[i + 1] = ""; return newString; } if (options[i].charAt(1) == '-') { return ""; } } return ""; } /** * Gets the index of an option or flag indicated by a flag "-Char" from * the given array of strings. Stops searching at the first marker "--". * * @param flag the character indicating the option. * @param options the array of strings containing all the options. * @return the position if found, or -1 otherwise */ public static int getOptionPos(char flag, String[] options) { return getOptionPos("" + flag, options); } /** * Gets the index of an option or flag indicated by a flag "-String" from * the given array of strings. Stops searching at the first marker "--". * * @param flag the String indicating the option. * @param options the array of strings containing all the options. * @return the position if found, or -1 otherwise */ public static int getOptionPos(String flag, String[] options) { if (options == null) return -1; for (int i = 0; i < options.length; i++) { if ((options[i].length() > 0) && (options[i].charAt(0) == '-')) { // Check if it is a negative number try { Double.valueOf(options[i]); } catch (NumberFormatException e) { // found? if (options[i].equals("-" + flag)) return i; // did we reach "--"? if (options[i].charAt(1) == '-') return -1; } } } return -1; } /** * Quotes a string if it contains special characters. * * The following rules are applied: * * A character is backquoted version of it is one * of <tt>" ' % \ \n \r \t</tt>. * * A string is enclosed within single quotes if a character has been * backquoted using the previous rule above or contains * <tt>{ }</tt> or is exactly equal to the strings * <tt>, ? space or ""</tt> (empty string). * * A quoted question mark distinguishes it from the missing value which * is represented as an unquoted question mark in arff files. * * @param string the string to be quoted * @return the string (possibly quoted) * @see #unquote(String) */ public static /*@pure@*/ String quote(String string) { boolean quote = false; // backquote the following characters if ((string.indexOf('\n') != -1) || (string.indexOf('\r') != -1) || (string.indexOf('\'') != -1) || (string.indexOf('"') != -1) || (string.indexOf('\\') != -1) || (string.indexOf('\t') != -1) || (string.indexOf('%') != -1) || (string.indexOf('\u001E') != -1)) { string = backQuoteChars(string); quote = true; } // Enclose the string in 's if the string contains a recently added // backquote or contains one of the following characters. if((quote == true) || (string.indexOf('{') != -1) || (string.indexOf('}') != -1) || (string.indexOf(',') != -1) || (string.equals("?")) || (string.indexOf(' ') != -1) || (string.equals(""))) { string = ("'".concat(string)).concat("'"); } return string; } /** * unquotes are previously quoted string (but only if necessary), i.e., it * removes the single quotes around it. Inverse to quote(String). * * @param string the string to process * @return the unquoted string * @see #quote(String) */ public static String unquote(String string) { if (string.startsWith("'") && string.endsWith("'")) { string = string.substring(1, string.length() - 1); if ((string.indexOf("\\n") != -1) || (string.indexOf("\\r") != -1) || (string.indexOf("\\'") != -1) || (string.indexOf("\\\"") != -1) || (string.indexOf("\\\\") != -1) || (string.indexOf("\\t") != -1) || (string.indexOf("\\%") != -1) || (string.indexOf("\\u001E") != -1)) { string = unbackQuoteChars(string); } } return string; } /** * Converts carriage returns and new lines in a string into \r and \n. * Backquotes the following characters: ` " \ \t and % * * @param string the string * @return the converted string * @see #unbackQuoteChars(String) */ public static /*@pure@*/ String backQuoteChars(String string) { int index; StringBuffer newStringBuffer; // replace each of the following characters with the backquoted version char charsFind[] = {'\\', '\'', '\t', '\n', '\r', '"', '%', '\u001E'}; String charsReplace[] = {"\\\\", "\\'", "\\t", "\\n", "\\r", "\\\"", "\\%", "\\u001E"}; for (int i = 0; i < charsFind.length; i++) { if (string.indexOf(charsFind[i]) != -1 ) { newStringBuffer = new StringBuffer(); while ((index = string.indexOf(charsFind[i])) != -1) { if (index > 0) { newStringBuffer.append(string.substring(0, index)); } newStringBuffer.append(charsReplace[i]); if ((index + 1) < string.length()) { string = string.substring(index + 1); } else { string = ""; } } newStringBuffer.append(string); string = newStringBuffer.toString(); } } return string; } /** * Converts carriage returns and new lines in a string into \r and \n. * * @param string the string * @return the converted string */ public static String convertNewLines(String string) { int index; // Replace with \n StringBuffer newStringBuffer = new StringBuffer(); while ((index = string.indexOf('\n')) != -1) { if (index > 0) { newStringBuffer.append(string.substring(0, index)); } newStringBuffer.append('\\'); newStringBuffer.append('n'); if ((index + 1) < string.length()) { string = string.substring(index + 1); } else { string = ""; } } newStringBuffer.append(string); string = newStringBuffer.toString(); // Replace with \r newStringBuffer = new StringBuffer(); while ((index = string.indexOf('\r')) != -1) { if (index > 0) { newStringBuffer.append(string.substring(0, index)); } newStringBuffer.append('\\'); newStringBuffer.append('r'); if ((index + 1) < string.length()){ string = string.substring(index + 1); } else { string = ""; } } newStringBuffer.append(string); return newStringBuffer.toString(); } /** * Reverts \r and \n in a string into carriage returns and new lines. * * @param string the string * @return the converted string */ public static String revertNewLines(String string) { int index; // Replace with \n StringBuffer newStringBuffer = new StringBuffer(); while ((index = string.indexOf("\\n")) != -1) { if (index > 0) { newStringBuffer.append(string.substring(0, index)); } newStringBuffer.append('\n'); if ((index + 2) < string.length()) { string = string.substring(index + 2); } else { string = ""; } } newStringBuffer.append(string); string = newStringBuffer.toString(); // Replace with \r newStringBuffer = new StringBuffer(); while ((index = string.indexOf("\\r")) != -1) { if (index > 0) { newStringBuffer.append(string.substring(0, index)); } newStringBuffer.append('\r'); if ((index + 2) < string.length()){ string = string.substring(index + 2); } else { string = ""; } } newStringBuffer.append(string); return newStringBuffer.toString(); } /** * Returns the secondary set of options (if any) contained in * the supplied options array. The secondary set is defined to * be any options after the first "--". These options are removed from * the original options array. * * @param options the input array of options * @return the array of secondary options */ public static String[] partitionOptions(String[] options) { for (int i = 0; i < options.length; i++) { if (options[i].equals("--")) { options[i++] = ""; String[] result = new String [options.length - i]; for (int j = i; j < options.length; j++) { result[j - i] = options[j]; options[j] = ""; } return result; } } return new String [0]; } /** * The inverse operation of backQuoteChars(). * Converts back-quoted carriage returns and new lines in a string * to the corresponding character ('\r' and '\n'). * Also "un"-back-quotes the following characters: ` " \ \t and % * * @param string the string * @return the converted string * @see #backQuoteChars(String) */ public static String unbackQuoteChars(String string) { int index; StringBuffer newStringBuffer; // replace each of the following characters with the backquoted version String charsFind[] = {"\\\\", "\\'", "\\t", "\\n", "\\r", "\\\"", "\\%", "\\u001E"}; char charsReplace[] = {'\\', '\'', '\t', '\n', '\r', '"', '%', '\u001E'}; int pos[] = new int[charsFind.length]; int curPos; String str = new String(string); newStringBuffer = new StringBuffer(); while (str.length() > 0) { // get positions and closest character to replace curPos = str.length(); index = -1; for (int i = 0; i < pos.length; i++) { pos[i] = str.indexOf(charsFind[i]); if ( (pos[i] > -1) && (pos[i] < curPos) ) { index = i; curPos = pos[i]; } } // replace character if found, otherwise finished if (index == -1) { newStringBuffer.append(str); str = ""; } else { newStringBuffer.append(str.substring(0, pos[index])); newStringBuffer.append(charsReplace[index]); str = str.substring(pos[index] + charsFind[index].length()); } } return newStringBuffer.toString(); } /** * Split up a string containing options into an array of strings, * one for each option. * * @param quotedOptionString the string containing the options * @return the array of options * @throws Exception in case of an unterminated string, unknown character or * a parse error */ public static String[] splitOptions(String quotedOptionString) throws Exception{ Vector<String> optionsVec = new Vector<String>(); String str = new String(quotedOptionString); int i; while (true){ //trimLeft i = 0; while ((i < str.length()) && (Character.isWhitespace(str.charAt(i)))) i++; str = str.substring(i); //stop when str is empty if (str.length() == 0) break; //if str start with a double quote if (str.charAt(0) == '"'){ //find the first not anti-slached double quote i = 1; while(i < str.length()){ if (str.charAt(i) == str.charAt(0)) break; if (str.charAt(i) == '\\'){ i += 1; if (i >= str.length()) throw new Exception("String should not finish with \\"); } i += 1; } if (i >= str.length()) throw new Exception("Quote parse error."); //add the founded string to the option vector (without quotes) String optStr = str.substring(1,i); optStr = unbackQuoteChars(optStr); optionsVec.addElement(optStr); str = str.substring(i+1); } else { //find first whiteSpace i=0; while((i < str.length()) && (!Character.isWhitespace(str.charAt(i)))) i++; //add the founded string to the option vector String optStr = str.substring(0,i); optionsVec.addElement(optStr); str = str.substring(i); } } //convert optionsVec to an array of String String[] options = new String[optionsVec.size()]; for (i = 0; i < optionsVec.size(); i++) { options[i] = (String)optionsVec.elementAt(i); } return options; } /** * Joins all the options in an option array into a single string, * as might be used on the command line. * * @param optionArray the array of options * @return the string containing all options. */ public static String joinOptions(String[] optionArray) { String optionString = ""; for (int i = 0; i < optionArray.length; i++) { if (optionArray[i].equals("")) { continue; } boolean escape = false; for (int n = 0; n < optionArray[i].length(); n++) { if (Character.isWhitespace(optionArray[i].charAt(n))) { escape = true; break; } } if (escape) { optionString += '"' + backQuoteChars(optionArray[i]) + '"'; } else { optionString += optionArray[i]; } optionString += " "; } return optionString.trim(); } /** * Creates a new instance of an object given it's class name and * (optional) arguments to pass to it's setOptions method. If the * object implements OptionHandler and the options parameter is * non-null, the object will have it's options set. Example use:<p> * * <code> <pre> * String classifierName = Utils.getOption('W', options); * Classifier c = (Classifier)Utils.forName(Classifier.class, * classifierName, * options); * setClassifier(c); * </pre></code> * * @param classType the class that the instantiated object should * be assignable to -- an exception is thrown if this is not the case * @param className the fully qualified class name of the object * @param options an array of options suitable for passing to setOptions. May * be null. Any options accepted by the object will be removed from the * array. * @return the newly created object, ready for use. * @exception Exception if the class name is invalid, or if the * class is not assignable to the desired class type, or the options * supplied are not acceptable to the object */ public static Object forName(Class<?> classType, String className, String[] options) throws Exception { Class<?> c = null; try { c = Class.forName(className); } catch (Exception ex) { throw new Exception("Can't find class called: " + className); } if (!classType.isAssignableFrom(c)) { throw new Exception(classType.getName() + " is not assignable from " + className); } Object o = c.newInstance(); if ((o instanceof OptionHandler) && (options != null)) { ((OptionHandler)o).setOptions(options); Utils.checkForRemainingOptions(options); } return o; } /** * Generates a commandline of the given object. If the object is not * implementing OptionHandler, then it will only return the classname, * otherwise also the options. * * @param obj the object to turn into a commandline * @return the commandline */ public static String toCommandLine(Object obj) { StringBuffer result; result = new StringBuffer(); if (obj != null) { result.append(obj.getClass().getName()); if (obj instanceof OptionHandler) result.append(" " + joinOptions(((OptionHandler) obj).getOptions())); } return result.toString().trim(); } /** * Computes entropy for an array of integers. * * @param counts array of counts * @return - a log2 a - b log2 b - c log2 c + (a+b+c) log2 (a+b+c) * when given array [a b c] */ public static /*@pure@*/ double info(int counts[]) { int total = 0; double x = 0; for (int j = 0; j < counts.length; j++) { x -= xlogx(counts[j]); total += counts[j]; } return x + xlogx(total); } /** * Tests if a is smaller or equal to b. * * @param a a double * @param b a double */ public static /*@pure@*/ boolean smOrEq(double a,double b) { return (a-b < SMALL) || (a <= b); } /** * Tests if a is greater or equal to b. * * @param a a double * @param b a double */ public static /*@pure@*/ boolean grOrEq(double a,double b) { return (b-a < SMALL) || (a >= b); } /** * Tests if a is smaller than b. * * @param a a double * @param b a double */ public static /*@pure@*/ boolean sm(double a,double b) { return (b-a > SMALL); } /** * Tests if a is greater than b. * * @param a a double * @param b a double */ public static /*@pure@*/ boolean gr(double a,double b) { return (a-b > SMALL); } /** * Returns the kth-smallest value in the array. * * @param array the array of integers * @param k the value of k * @return the kth-smallest value */ public static int kthSmallestValue(int[] array, int k) { int[] index = initialIndex(array.length); return array[index[select(array, index, 0, array.length - 1, k)]]; } /** * Returns the kth-smallest value in the array * * @param array the array of double * @param k the value of k * @return the kth-smallest value */ public static double kthSmallestValue(double[] array, int k) { int[] index = initialIndex(array.length); return array[index[select(array, index, 0, array.length - 1, k)]]; } /** * Returns the logarithm of a for base 2. * * @param a a double * @return the logarithm for base 2 */ public static /*@pure@*/ double log2(double a) { return Math.log(a) / log2; } /** * Returns index of maximum element in a given * array of doubles. First maximum is returned. * * @param doubles the array of doubles * @return the index of the maximum element */ public static /*@pure@*/ int maxIndex(double[] doubles) { double maximum = 0; int maxIndex = 0; for (int i = 0; i < doubles.length; i++) { if ((i == 0) || (doubles[i] > maximum)) { maxIndex = i; maximum = doubles[i]; } } return maxIndex; } /** * Returns index of maximum element in a given * array of integers. First maximum is returned. * * @param ints the array of integers * @return the index of the maximum element */ public static /*@pure@*/ int maxIndex(int[] ints) { int maximum = 0; int maxIndex = 0; for (int i = 0; i < ints.length; i++) { if ((i == 0) || (ints[i] > maximum)) { maxIndex = i; maximum = ints[i]; } } return maxIndex; } /** * Computes the mean for an array of doubles. * * @param vector the array * @return the mean */ public static /*@pure@*/ double mean(double[] vector) { double sum = 0; if (vector.length == 0) { return 0; } for (int i = 0; i < vector.length; i++) { sum += vector[i]; } return sum / (double) vector.length; } /** * Returns index of minimum element in a given * array of integers. First minimum is returned. * * @param ints the array of integers * @return the index of the minimum element */ public static /*@pure@*/ int minIndex(int[] ints) { int minimum = 0; int minIndex = 0; for (int i = 0; i < ints.length; i++) { if ((i == 0) || (ints[i] < minimum)) { minIndex = i; minimum = ints[i]; } } return minIndex; } /** * Returns index of minimum element in a given * array of doubles. First minimum is returned. * * @param doubles the array of doubles * @return the index of the minimum element */ public static /*@pure@*/ int minIndex(double[] doubles) { double minimum = 0; int minIndex = 0; for (int i = 0; i < doubles.length; i++) { if ((i == 0) || (doubles[i] < minimum)) { minIndex = i; minimum = doubles[i]; } } return minIndex; } /** * Normalizes the doubles in the array by their sum. * * @param doubles the array of double * @exception IllegalArgumentException if sum is Zero or NaN */ public static void normalize(double[] doubles) { double sum = 0; for (int i = 0; i < doubles.length; i++) { sum += doubles[i]; } normalize(doubles, sum); } /** * Normalizes the doubles in the array using the given value. * * @param doubles the array of double * @param sum the value by which the doubles are to be normalized * @exception IllegalArgumentException if sum is zero or NaN */ public static void normalize(double[] doubles, double sum) { if (Double.isNaN(sum)) { throw new IllegalArgumentException("Can't normalize array. Sum is NaN."); } if (sum == 0) { // Maybe this should just be a return. throw new IllegalArgumentException("Can't normalize array. Sum is zero."); } for (int i = 0; i < doubles.length; i++) { doubles[i] /= sum; } } /** * Converts an array containing the natural logarithms of * probabilities stored in a vector back into probabilities. * The probabilities are assumed to sum to one. * * @param a an array holding the natural logarithms of the probabilities * @return the converted array */ public static double[] logs2probs(double[] a) { double max = a[maxIndex(a)]; double sum = 0.0; double[] result = new double[a.length]; for(int i = 0; i < a.length; i++) { result[i] = Math.exp(a[i] - max); sum += result[i]; } normalize(result, sum); return result; } /** * Returns the log-odds for a given probabilitiy. * * @param prob the probabilitiy * * @return the log-odds after the probability has been mapped to * [Utils.SMALL, 1-Utils.SMALL] */ public static /*@pure@*/ double probToLogOdds(double prob) { if (gr(prob, 1) || (sm(prob, 0))) { throw new IllegalArgumentException("probToLogOdds: probability must " + "be in [0,1] "+prob); } double p = SMALL + (1.0 - 2 * SMALL) * prob; return Math.log(p / (1 - p)); } /** * Rounds a double to the next nearest integer value. The JDK version * of it doesn't work properly. * * @param value the double value * @return the resulting integer value */ public static /*@pure@*/ int round(double value) { int roundedValue = value > 0 ? (int)(value + 0.5) : -(int)(Math.abs(value) + 0.5); return roundedValue; } /** * Rounds a double to the next nearest integer value in a probabilistic * fashion (e.g. 0.8 has a 20% chance of being rounded down to 0 and a * 80% chance of being rounded up to 1). In the limit, the average of * the rounded numbers generated by this procedure should converge to * the original double. * * @param value the double value * @param rand the random number generator * @return the resulting integer value */ public static int probRound(double value, Random rand) { if (value >= 0) { double lower = Math.floor(value); double prob = value - lower; if (rand.nextDouble() < prob) { return (int)lower + 1; } else { return (int)lower; } } else { double lower = Math.floor(Math.abs(value)); double prob = Math.abs(value) - lower; if (rand.nextDouble() < prob) { return -((int)lower + 1); } else { return -(int)lower; } } } /** * Replaces all "missing values" in the given array of double values with * MAX_VALUE. * * @param array the array to be modified. */ public static void replaceMissingWithMAX_VALUE(double[] array) { for (int i = 0; i < array.length; i++) { if (isMissingValue(array[i])) { array[i] = Double.MAX_VALUE; } } } /** * Rounds a double to the given number of decimal places. * * @param value the double value * @param afterDecimalPoint the number of digits after the decimal point * @return the double rounded to the given precision */ public static /*@pure@*/ double roundDouble(double value,int afterDecimalPoint) { double mask = Math.pow(10.0, (double)afterDecimalPoint); return (double)(Math.round(value * mask)) / mask; } /** * Sorts a given array of integers in ascending order and returns an * array of integers with the positions of the elements of the original * array in the sorted array. The sort is stable. (Equal elements remain * in their original order.) * * @param array this array is not changed by the method! * @return an array of integers with the positions in the sorted * array. */ public static /*@pure@*/ int[] sort(int[] array) { int[] index = initialIndex(array.length); int[] newIndex = new int[array.length]; int[] helpIndex; int numEqual; quickSort(array, index, 0, array.length - 1); // Make sort stable int i = 0; while (i < index.length) { numEqual = 1; for (int j = i + 1; ((j < index.length) && (array[index[i]] == array[index[j]])); j++) { numEqual++; } if (numEqual > 1) { helpIndex = new int[numEqual]; for (int j = 0; j < numEqual; j++) { helpIndex[j] = i + j; } quickSort(index, helpIndex, 0, numEqual - 1); for (int j = 0; j < numEqual; j++) { newIndex[i + j] = index[helpIndex[j]]; } i += numEqual; } else { newIndex[i] = index[i]; i++; } } return newIndex; } /** * Sorts a given array of doubles in ascending order and returns an * array of integers with the positions of the elements of the * original array in the sorted array. NOTE THESE CHANGES: the sort * is no longer stable and it doesn't use safe floating-point * comparisons anymore. Occurrences of Double.NaN are treated as * Double.MAX_VALUE. * * @param array this array is not changed by the method! * @return an array of integers with the positions in the sorted * array. */ public static /*@pure@*/ int[] sort(/*@non_null@*/ double[] array) { int[] index = initialIndex(array.length); if (array.length > 1) { array = (double[])array.clone(); replaceMissingWithMAX_VALUE(array); quickSort(array, index, 0, array.length - 1); } return index; } /** * Sorts a given array of doubles in ascending order and returns an * array of integers with the positions of the elements of the * original array in the sorted array. Missing values in the given * array are replaced by Double.MAX_VALUE, so the array is modified in that case! * * @param array the array to be sorted, which is modified if it has missing values * @return an array of integers with the positions in the sorted * array. */ public static /*@pure@*/ int[] sortWithNoMissingValues(/*@non_null@*/ double[] array) { int[] index = initialIndex(array.length); if (array.length > 1) { quickSort(array, index, 0, array.length - 1); } return index; } /** * Sorts a given array of doubles in ascending order and returns an * array of integers with the positions of the elements of the original * array in the sorted array. The sort is stable (Equal elements remain * in their original order.) Occurrences of Double.NaN are treated as * Double.MAX_VALUE * * @param array this array is not changed by the method! * @return an array of integers with the positions in the sorted * array. */ public static /*@pure@*/ int[] stableSort(double[] array){ int[] index = initialIndex(array.length); if (array.length > 1) { int[] newIndex = new int[array.length]; int[] helpIndex; int numEqual; array = (double[])array.clone(); replaceMissingWithMAX_VALUE(array); quickSort(array, index, 0, array.length-1); // Make sort stable int i = 0; while (i < index.length) { numEqual = 1; for (int j = i+1; ((j < index.length) && Utils.eq(array[index[i]], array[index[j]])); j++) numEqual++; if (numEqual > 1) { helpIndex = new int[numEqual]; for (int j = 0; j < numEqual; j++) helpIndex[j] = i+j; quickSort(index, helpIndex, 0, numEqual-1); for (int j = 0; j < numEqual; j++) newIndex[i+j] = index[helpIndex[j]]; i += numEqual; } else { newIndex[i] = index[i]; i++; } } return newIndex; } else { return index; } } /** * Computes the variance for an array of doubles. * * @param vector the array * @return the variance */ public static /*@pure@*/ double variance(double[] vector) { double sum = 0, sumSquared = 0; if (vector.length <= 1) { return 0; } for (int i = 0; i < vector.length; i++) { sum += vector[i]; sumSquared += (vector[i] * vector[i]); } double result = (sumSquared - (sum * sum / (double) vector.length)) / (double) (vector.length - 1); // We don't like negative variance if (result < 0) { return 0; } else { return result; } } /** * Computes the sum of the elements of an array of doubles. * * @param doubles the array of double * @return the sum of the elements */ public static /*@pure@*/ double sum(double[] doubles) { double sum = 0; for (int i = 0; i < doubles.length; i++) { sum += doubles[i]; } return sum; } /** * Computes the sum of the elements of an array of integers. * * @param ints the array of integers * @return the sum of the elements */ public static /*@pure@*/ int sum(int[] ints) { int sum = 0; for (int i = 0; i < ints.length; i++) { sum += ints[i]; } return sum; } /** * Returns c*log2(c) for a given integer value c. * * @param c an integer value * @return c*log2(c) (but is careful to return 0 if c is 0) */ public static /*@pure@*/ double xlogx(int c) { if (c == 0) { return 0.0; } return c * Utils.log2((double) c); } /** * Initial index, filled with values from 0 to size - 1. */ private static int[] initialIndex(int size) { int[] index = new int[size]; for (int i = 0; i < size; i++) { index[i] = i; } return index; } /** * Sorts left, right, and center elements only, returns resulting center as pivot. */ private static int sortLeftRightAndCenter(double[] array, int[] index, int l, int r) { int c = (l + r) / 2; conditionalSwap(array, index, l, c); conditionalSwap(array, index, l, r); conditionalSwap(array, index, c, r); return c; } /** * Swaps two elements in the given integer array. */ private static void swap(int[] index, int l, int r) { int help = index[l]; index[l] = index[r]; index[r] = help; } /** * Conditional swap for quick sort. */ private static void conditionalSwap(double[] array, int[] index, int left, int right) { if (array[index[left]] > array[index[right]]) { int help = index[left]; index[left] = index[right]; index[right] = help; } } /** * Partitions the instances around a pivot. Used by quicksort and * kthSmallestValue. * * @param array the array of doubles to be sorted * @param index the index into the array of doubles * @param l the first index of the subset * @param r the last index of the subset * * @return the index of the middle element */ private static int partition(double[] array, int[] index, int l, int r, double pivot) { r--; while (true) { while ((array[index[++l]] < pivot)); while ((array[index[--r]] > pivot)); if (l >= r) { return l; } swap(index, l, r); } } /** * Partitions the instances around a pivot. Used by quicksort and * kthSmallestValue. * * @param array the array of integers to be sorted * @param index the index into the array of integers * @param l the first index of the subset * @param r the last index of the subset * * @return the index of the middle element */ private static int partition(int[] array, int[] index, int l, int r) { double pivot = array[index[(l + r) / 2]]; int help; while (l < r) { while ((array[index[l]] < pivot) && (l < r)) { l++; } while ((array[index[r]] > pivot) && (l < r)) { r--; } if (l < r) { help = index[l]; index[l] = index[r]; index[r] = help; l++; r--; } } if ((l == r) && (array[index[r]] > pivot)) { r--; } return r; } /** * Implements quicksort with median-of-three method and explicit sort for * problems of size three or less. * * @param array the array of doubles to be sorted * @param index the index into the array of doubles * @param left the first index of the subset to be sorted * @param right the last index of the subset to be sorted */ //@ requires 0 <= first && first <= right && right < array.length; //@ requires (\forall int i; 0 <= i && i < index.length; 0 <= index[i] && index[i] < array.length); //@ requires array != index; // assignable index; private static void quickSort(/*@non_null@*/ double[] array, /*@non_null@*/ int[] index, int left, int right) { int diff = right - left; switch (diff) { case 0 : // No need to do anything return; case 1 : // Swap two elements if necessary conditionalSwap(array, index, left, right); return; case 2 : // Just need to sort three elements conditionalSwap(array, index, left, left + 1); conditionalSwap(array, index, left, right); conditionalSwap(array, index, left + 1, right); return; default : // Establish pivot int pivotLocation = sortLeftRightAndCenter(array, index, left, right); // Move pivot to the right, partition, and restore pivot swap(index, pivotLocation, right - 1); int center = partition(array, index, left, right, array[index[right - 1]]); swap(index, center, right - 1); // Sort recursively quickSort(array, index, left, center - 1); quickSort(array, index, center + 1, right); } } /** * Implements quicksort according to Manber's "Introduction to * Algorithms". * * @param array the array of integers to be sorted * @param index the index into the array of integers * @param left the first index of the subset to be sorted * @param right the last index of the subset to be sorted */ //@ requires 0 <= first && first <= right && right < array.length; //@ requires (\forall int i; 0 <= i && i < index.length; 0 <= index[i] && index[i] < array.length); //@ requires array != index; // assignable index; private static void quickSort(/*@non_null@*/ int[] array, /*@non_null@*/ int[] index, int left, int right) { if (left < right) { int middle = partition(array, index, left, right); quickSort(array, index, left, middle); quickSort(array, index, middle + 1, right); } } /** * Implements computation of the kth-smallest element according * to Manber's "Introduction to Algorithms". * * @param array the array of double * @param index the index into the array of doubles * @param left the first index of the subset * @param right the last index of the subset * @param k the value of k * * @return the index of the kth-smallest element */ //@ requires 0 <= first && first <= right && right < array.length; private static int select(/*@non_null@*/ double[] array, /*@non_null@*/ int[] index, int left, int right, int k) { int diff = right - left; switch (diff) { case 0 : // Nothing to be done return left; case 1 : // Swap two elements if necessary conditionalSwap(array, index, left, right); return left + k - 1; case 2 : // Just need to sort three elements conditionalSwap(array, index, left, left + 1); conditionalSwap(array, index, left, right); conditionalSwap(array, index, left + 1, right); return left + k - 1; default : // Establish pivot int pivotLocation = sortLeftRightAndCenter(array, index, left, right); // Move pivot to the right, partition, and restore pivot swap(index, pivotLocation, right - 1); int center = partition(array, index, left, right, array[index[right - 1]]); swap(index, center, right - 1); // Proceed recursively if ((center - left + 1) >= k) { return select(array, index, left, center, k); } else { return select(array, index, center + 1, right, k - (center - left + 1)); } } } /** * Converts a File's absolute path to a path relative to the user * (ie start) directory. Includes an additional workaround for Cygwin, which * doesn't like upper case drive letters. * @param absolute the File to convert to relative path * @return a File with a path that is relative to the user's directory * @exception Exception if the path cannot be constructed */ public static File convertToRelativePath(File absolute) throws Exception { File result; String fileStr; result = null; // if we're running windows, it could be Cygwin if (File.separator.equals("\\")) { // Cygwin doesn't like upper case drives -> try lower case drive try { fileStr = absolute.getPath(); fileStr = fileStr.substring(0, 1).toLowerCase() + fileStr.substring(1); result = createRelativePath(new File(fileStr)); } catch (Exception e) { // no luck with Cygwin workaround, convert it like it is result = createRelativePath(absolute); } } else { result = createRelativePath(absolute); } return result; } /** * Converts a File's absolute path to a path relative to the user * (ie start) directory. * * @param absolute the File to convert to relative path * @return a File with a path that is relative to the user's directory * @exception Exception if the path cannot be constructed */ protected static File createRelativePath(File absolute) throws Exception { File userDir = new File(System.getProperty("user.dir")); String userPath = userDir.getAbsolutePath() + File.separator; String targetPath = (new File(absolute.getParent())).getPath() + File.separator; String fileName = absolute.getName(); StringBuffer relativePath = new StringBuffer(); // relativePath.append("."+File.separator); // System.err.println("User dir "+userPath); // System.err.println("Target path "+targetPath); // file is in user dir (or subdir) int subdir = targetPath.indexOf(userPath); if (subdir == 0) { if (userPath.length() == targetPath.length()) { relativePath.append(fileName); } else { int ll = userPath.length(); relativePath.append(targetPath.substring(ll)); relativePath.append(fileName); } } else { int sepCount = 0; String temp = new String(userPath); while (temp.indexOf(File.separator) != -1) { int ind = temp.indexOf(File.separator); sepCount++; temp = temp.substring(ind+1, temp.length()); } String targetTemp = new String(targetPath); String userTemp = new String(userPath); int tcount = 0; while (targetTemp.indexOf(File.separator) != -1) { int ind = targetTemp.indexOf(File.separator); int ind2 = userTemp.indexOf(File.separator); String tpart = targetTemp.substring(0,ind+1); String upart = userTemp.substring(0,ind2+1); if (tpart.compareTo(upart) != 0) { if (tcount == 0) { tcount = -1; } break; } tcount++; targetTemp = targetTemp.substring(ind+1, targetTemp.length()); userTemp = userTemp.substring(ind2+1, userTemp.length()); } if (tcount == -1) { // then target file is probably on another drive (under windows) throw new Exception("Can't construct a path to file relative to user " +"dir."); } if (targetTemp.indexOf(File.separator) == -1) { targetTemp = ""; } for (int i = 0; i < sepCount - tcount; i++) { relativePath.append(".."+File.separator); } relativePath.append(targetTemp + fileName); } // System.err.println("new path : "+relativePath.toString()); return new File(relativePath.toString()); } /** * Implements computation of the kth-smallest element according * to Manber's "Introduction to Algorithms". * * @param array the array of integers * @param index the index into the array of integers * @param left the first index of the subset * @param right the last index of the subset * @param k the value of k * * @return the index of the kth-smallest element */ //@ requires 0 <= first && first <= right && right < array.length; private static int select(/*@non_null@*/ int[] array, /*@non_null@*/ int[] index, int left, int right, int k) { if (left == right) { return left; } else { int middle = partition(array, index, left, right); if ((middle - left + 1) >= k) { return select(array, index, left, middle, k); } else { return select(array, index, middle + 1, right, k - (middle - left + 1)); } } } /** * For a named dialog, returns true if the user has opted not to view * it again in the future. * * @param dialogName the name of the dialog to check (e.g. * weka.gui.GUICHooser.HowToFindPackageManager). * @return true if the user has opted not to view the named dialog * in the future. public static boolean getDontShowDialog(String dialogName) { File wekaHome = WekaPackageManager.WEKA_HOME; if (!wekaHome.exists()) { return false; } File dialogSubDir = new File(wekaHome.toString() + File.separator + "systemDialogs"); if (!dialogSubDir.exists()) { return false; } File dialogFile = new File(dialogSubDir.toString() + File.separator + dialogName); return dialogFile.exists(); } */ /** * Specify that the named dialog is not to be displayed in the future. * * @param dialogName the name of the dialog not to show again (e.g. * weka.gui.GUIChooser.HowToFindPackageManager). * @throws Exception if the marker file that is used to indicate that * a named dialog is not to be shown can't be created. This file lives * in $WEKA_HOME/systemDialogs public static void setDontShowDialog(String dialogName) throws Exception { File wekaHome = WekaPackageManager.WEKA_HOME; if (!wekaHome.exists()) { return; } File dialogSubDir = new File(wekaHome.toString() + File.separator + "systemDialogs"); if (!dialogSubDir.exists()) { if (!dialogSubDir.mkdir()) { return; } } File dialogFile = new File(dialogSubDir.toString() + File.separator + dialogName); dialogFile.createNewFile(); } */ /** * For a named dialog, if the user has opted not to view it again, * returns the answer the answer the user supplied when they * closed the dialog. Returns null if the user did opt to view * the dialog again. * * @param dialogName the name of the dialog to check (e.g. * weka.gui.GUICHooser.HowToFindPackageManager). * @return the answer the user supplied the last time they * viewed the named dialog (if they opted not to view it again * in the future) or null if the user opted to view the dialog * again in the future. public static String getDontShowDialogResponse(String dialogName) throws Exception { if (!getDontShowDialog(dialogName)) { return null; // This must be the first time - no file recorded yet. } File wekaHome = WekaPackageManager.WEKA_HOME; File dialogSubDir = new File(wekaHome.toString() + File.separator + "systemDialogs" + File.separator + dialogName); BufferedReader br = new BufferedReader(new FileReader(dialogSubDir)); String response = br.readLine(); br.close(); return response; } */ /** * Specify that the named dialog is not to be shown again in the future. * Also records the answer that the user chose when closing the dialog. * * @param dialogName the name of the dialog to no longer display * @param response the user selected response when they closed the dialog * @throws Exception if there is a problem saving the information public static void setDontShowDialogResponse(String dialogName, String response) throws Exception { File wekaHome = WekaPackageManager.WEKA_HOME; if (!wekaHome.exists()) { return; } File dialogSubDir = new File(wekaHome.toString() + File.separator + "systemDialogs"); if (!dialogSubDir.exists()) { if (!dialogSubDir.mkdir()) { return; } } File dialogFile = new File(dialogSubDir.toString() + File.separator + dialogName); BufferedWriter br = new BufferedWriter(new FileWriter(dialogFile)); br.write(response + "\n"); br.flush(); br.close(); } */ /** * Breaks up the string, if wider than "columns" characters. * * @param s the string to process * @param columns the width in columns * @return the processed string */ public static String[] breakUp(String s, int columns) { Vector<String> result; String line; BreakIterator boundary; int boundaryStart; int boundaryEnd; String word; String punctuation; int i; String[] lines; result = new Vector<String>(); punctuation = " .,;:!?'\""; lines = s.split("\n"); for (i = 0; i < lines.length; i++) { boundary = BreakIterator.getWordInstance(); boundary.setText(lines[i]); boundaryStart = boundary.first(); boundaryEnd = boundary.next(); line = ""; while (boundaryEnd != BreakIterator.DONE) { word = lines[i].substring(boundaryStart, boundaryEnd); if (line.length() >= columns) { if (word.length() == 1) { if (punctuation.indexOf(word.charAt(0)) > -1) { line += word; word = ""; } } result.add(line); line = ""; } line += word; boundaryStart = boundaryEnd; boundaryEnd = boundary.next(); } if (line.length() > 0) result.add(line); } return result.toArray(new String[result.size()]); } /** * Returns the revision string. * * @return the revision */ public String getRevision() { return RevisionUtils.extract("$Revision: 9736 $"); } /** * Main method for testing this class. * * @param ops some dummy options */ public static void main(String[] ops) { double[] doublesWithNaN = {4.5, 6.7, Double.NaN, 3.4, 4.8, 1.2, 3.4}; double[] doubles = {4.5, 6.7, 6.7, 3.4, 4.8, 1.2, 3.4, 6.7, 6.7, 3.4}; int[] ints = {12, 6, 2, 18, 16, 6, 7, 5, 18, 18, 17}; try { // Option handling System.out.println("First option split up:"); if (ops.length > 0) { String[] firstOptionSplitUp = Utils.splitOptions(ops[0]); for (int i = 0; i < firstOptionSplitUp.length; i ++) { System.out.println(firstOptionSplitUp[i]); } } System.out.println("Partitioned options: "); String[] partitionedOptions = Utils.partitionOptions(ops); for (int i = 0; i < partitionedOptions.length; i++) { System.out.println(partitionedOptions[i]); } System.out.println("Get position of flag -f: " + Utils.getOptionPos('f', ops)); System.out.println("Get flag -f: " + Utils.getFlag('f', ops)); System.out.println("Get position of option -o: " + Utils.getOptionPos('o', ops)); System.out.println("Get option -o: " + Utils.getOption('o', ops)); System.out.println("Checking for remaining options... "); Utils.checkForRemainingOptions(ops); // Statistics System.out.println("Original array with NaN (doubles): "); for (int i = 0; i < doublesWithNaN.length; i++) { System.out.print(doublesWithNaN[i] + " "); } System.out.println(); System.out.println("Original array (doubles): "); for (int i = 0; i < doubles.length; i++) { System.out.print(doubles[i] + " "); } System.out.println(); System.out.println("Original array (ints): "); for (int i = 0; i < ints.length; i++) { System.out.print(ints[i] + " "); } System.out.println(); System.out.println("Correlation: " + Utils.correlation(doubles, doubles, doubles.length)); System.out.println("Mean: " + Utils.mean(doubles)); System.out.println("Variance: " + Utils.variance(doubles)); System.out.println("Sum (doubles): " + Utils.sum(doubles)); System.out.println("Sum (ints): " + Utils.sum(ints)); System.out.println("Max index (doubles): " + Utils.maxIndex(doubles)); System.out.println("Max index (ints): " + Utils.maxIndex(ints)); System.out.println("Min index (doubles): " + Utils.minIndex(doubles)); System.out.println("Min index (ints): " + Utils.minIndex(ints)); System.out.println("Median (doubles): " + Utils.kthSmallestValue(doubles, doubles.length / 2)); System.out.println("Median (ints): " + Utils.kthSmallestValue(ints, ints.length / 2)); // Sorting and normalizing System.out.println("Sorted array with NaN (doubles): "); int[] sorted = Utils.sort(doublesWithNaN); for (int i = 0; i < doublesWithNaN.length; i++) { System.out.print(doublesWithNaN[sorted[i]] + " "); } System.out.println(); System.out.println("Sorted array (doubles): "); sorted = Utils.sort(doubles); for (int i = 0; i < doubles.length; i++) { System.out.print(doubles[sorted[i]] + " "); } System.out.println(); System.out.println("Sorted array (ints): "); sorted = Utils.sort(ints); for (int i = 0; i < ints.length; i++) { System.out.print(ints[sorted[i]] + " "); } System.out.println(); System.out.println("Indices from stable sort (doubles): "); sorted = Utils.stableSort(doubles); for (int i = 0; i < doubles.length; i++) { System.out.print(sorted[i] + " "); } System.out.println(); System.out.println("Indices from sort (ints): "); sorted = Utils.sort(ints); for (int i = 0; i < ints.length; i++) { System.out.print(sorted[i] + " "); } System.out.println(); System.out.println("Normalized array (doubles): "); Utils.normalize(doubles); for (int i = 0; i < doubles.length; i++) { System.out.print(doubles[i] + " "); } System.out.println(); System.out.println("Normalized again (doubles): "); Utils.normalize(doubles, Utils.sum(doubles)); for (int i = 0; i < doubles.length; i++) { System.out.print(doubles[i] + " "); } System.out.println(); // Pretty-printing System.out.println("-4.58: " + Utils.doubleToString(-4.57826535, 2)); System.out.println("-6.78: " + Utils.doubleToString(-6.78214234, 6,2)); // Comparisons System.out.println("5.70001 == 5.7 ? " + Utils.eq(5.70001, 5.7)); System.out.println("5.70001 > 5.7 ? " + Utils.gr(5.70001, 5.7)); System.out.println("5.70001 >= 5.7 ? " + Utils.grOrEq(5.70001, 5.7)); System.out.println("5.7 < 5.70001 ? " + Utils.sm(5.7, 5.70001)); System.out.println("5.7 <= 5.70001 ? " + Utils.smOrEq(5.7, 5.70001)); // Math System.out.println("Info (ints): " + Utils.info(ints)); System.out.println("log2(4.6): " + Utils.log2(4.6)); System.out.println("5 * log(5): " + Utils.xlogx(5)); System.out.println("5.5 rounded: " + Utils.round(5.5)); System.out.println("5.55555 rounded to 2 decimal places: " + Utils.roundDouble(5.55555, 2)); // Arrays System.out.println("Array-Dimensions of 'new int[][]': " + Utils.getArrayDimensions(new int[][]{})); System.out.println("Array-Dimensions of 'new int[][]{{1,2,3},{4,5,6}}': " + Utils.getArrayDimensions(new int[][]{{1,2,3},{4,5,6}})); String[][][] s = new String[3][4][]; System.out.println("Array-Dimensions of 'new String[3][4][]': " + Utils.getArrayDimensions(s)); } catch (Exception e) { e.printStackTrace(); } } }