source: src/main/java/weka/core/Utils.java @ 14

Last change on this file since 14 was 4, checked in by gnappo, 14 years ago

Import di weka.

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