001 package net.sf.cpsolver.ifs.util; 002 003 import java.io.*; 004 import java.util.*; 005 import org.apache.log4j.*; 006 007 /** Several auxiliary static methods. 008 * 009 * @version 010 * IFS 1.1 (Iterative Forward Search)<br> 011 * Copyright (C) 2006 Tomáš Müller<br> 012 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 013 * Lazenska 391, 76314 Zlin, Czech Republic<br> 014 * <br> 015 * This library is free software; you can redistribute it and/or 016 * modify it under the terms of the GNU Lesser General Public 017 * License as published by the Free Software Foundation; either 018 * version 2.1 of the License, or (at your option) any later version. 019 * <br><br> 020 * This library is distributed in the hope that it will be useful, 021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 023 * Lesser General Public License for more details. 024 * <br><br> 025 * You should have received a copy of the GNU Lesser General Public 026 * License along with this library; if not, write to the Free Software 027 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 028 */ 029 public class ToolBox { 030 private static long sSeed = System.currentTimeMillis(); 031 private static Random sRandom = new Random(sSeed); 032 033 /** Returns random number (int) from the set 0 .. limit - 1 */ 034 public static int random(int limit) { 035 return (int)(random()*limit); 036 } 037 038 /** Returns random element from the given set of elements */ 039 public static Object random(Collection set) { 040 if (set==null || set.size()==0) return null; 041 Vector v = (set instanceof Vector?(Vector)set:new Vector(set)); 042 return v.elementAt(random(v.size())); 043 } 044 045 /** Returns a randomly generated subset of the given set 046 * @param set set 047 * @param part probability of selection of an element into the resultant subset 048 */ 049 public static Collection subSet(Collection set, double part) { 050 return subSet(set,part,1); 051 } 052 053 /** Swaps two elements in the list */ 054 private static void swap(ArrayList list, int first, int second) { 055 Object o = list.get(first); 056 list.set(first,list.get(second)); 057 list.set(second,o); 058 } 059 060 /** Returns a randomly generated subset of the given set 061 * @param set set 062 * @param part probability of selection of an element into the resultant subset 063 * @param minSize minimal size of the returned subset 064 */ 065 public static Collection subSet(Collection set, double part, int minSize) { 066 if (set.size()<=minSize || part>=1.0) return set; 067 ArrayList subSet = new ArrayList(set); 068 int size = set.size(); 069 int numberToSelect = Math.max(minSize,(int)(part*set.size())); 070 for (int idx=0;idx<numberToSelect;idx++) { 071 swap(subSet, idx, idx+(int)(random()*(size-idx))); 072 } 073 return subSet.subList(0, numberToSelect); 074 } 075 076 /** Trim a string to have given length */ 077 public static String trim(String s, int length) { 078 if (s.length()>length) return s.substring(0,length); 079 StringBuffer sb = new StringBuffer(s); 080 while (sb.length()<length) sb.append(" "); 081 return sb.toString(); 082 } 083 084 /** Multiline representation of a colection */ 085 public static String col2string(Collection col, int tab) { 086 StringBuffer tabsb = new StringBuffer(); 087 while (tabsb.length()<2*tab) 088 tabsb.append(" "); 089 StringBuffer sb = new StringBuffer("[\n"); 090 for (Iterator i=col.iterator();i.hasNext();) { 091 sb.append(tabsb+" "+i.next()+(i.hasNext()?",":"")+"\n"); 092 } 093 sb.append(tabsb+"]"); 094 return sb.toString(); 095 } 096 097 /** Multiline representation of a dictionary */ 098 public static String dict2string(Dictionary dict, int tab) { 099 StringBuffer tabsb = new StringBuffer(); 100 while (tabsb.length()<2*tab) 101 tabsb.append(" "); 102 StringBuffer sb = new StringBuffer("[\n"); 103 for (Enumeration e=sortEnumeration(dict.keys());e.hasMoreElements();) { 104 Object key = e.nextElement(); 105 Object value = dict.get(key); 106 sb.append(tabsb+" "+key+": "+value+"\n"); 107 } 108 sb.append(tabsb+"]"); 109 return sb.toString(); 110 } 111 112 /** Root mean square 113 * @param n number of tests 114 * @param x total value of all tests 115 * @param x2 total value^2 of all tests 116 */ 117 public static double rms(int n, double x, double x2) { 118 double var = x2/n ; 119 double mean = x/n; 120 return Math.sqrt(Math.abs(var-mean*mean)); 121 } 122 123 /** Sort enumeration 124 * @param e an enumeration 125 * @return sorted enumeration 126 */ 127 public static Enumeration sortEnumeration(java.util.Enumeration e) { 128 return sortEnumeration(e,null); 129 } 130 131 /** Sort enumeration 132 * @param e an enumeration 133 * @param c comparator of two objects in enumeration e 134 * @return sorted enumeration 135 */ 136 public static Enumeration sortEnumeration(java.util.Enumeration e, java.util.Comparator c) { 137 Vector v = new Vector(); 138 for (;e.hasMoreElements();) v.addElement(e.nextElement()); 139 Collections.sort(v,c); 140 return v.elements(); 141 } 142 143 /** Merge source with target */ 144 public static void merge(Vector target, Collection source) { 145 for (Iterator i=source.iterator(); i.hasNext();) { 146 Object o = i.next(); 147 if (!target.contains(o)) target.addElement(o); 148 } 149 } 150 151 /** Returns intersection of two collections */ 152 public static Vector intersect(Collection source1, Collection source2) { 153 Vector target = new FastVector(); 154 for (Iterator i=source1.iterator(); i.hasNext();) { 155 Object o = i.next(); 156 if (!source2.contains(o)) target.addElement(o); 157 } 158 return target; 159 } 160 161 /** Sets seeds for {@link ToolBox#getRandom()} and {@link ToolBox#random()} methods. */ 162 public static void setSeed(long seed) { 163 sSeed = seed; 164 sRandom = new Random(sSeed); 165 } 166 167 /** Gets current seed */ 168 public static long getSeed() { 169 return sSeed; 170 } 171 /** Gets random number generator */ 172 public static Random getRandom() { 173 return sRandom; 174 } 175 /** Generates random double number */ 176 public static double random() { 177 return sRandom.nextDouble(); 178 } 179 180 /** Configurates log4j loging */ 181 public static void configureLogging() { 182 Properties props = new Properties(); 183 props.setProperty("log4j.rootLogger", "DEBUG, A1"); 184 props.setProperty("log4j.appender.A1", "org.apache.log4j.ConsoleAppender"); 185 props.setProperty("log4j.appender.A1.layout", "org.apache.log4j.PatternLayout"); 186 props.setProperty("log4j.appender.A1.layout.ConversionPattern","%-5p %c{2}: %m%n"); 187 props.setProperty("log4j.logger.net","INFO"); 188 props.setProperty("log4j.logger.net.sf.cpsolver","DEBUG"); 189 props.setProperty("log4j.logger.org","INFO"); 190 PropertyConfigurator.configure(props); 191 } 192 193 /** Configurates log4j loging 194 * @param logDir output folder 195 * @param properties some other log4j properties 196 */ 197 public static String configureLogging(String logDir, Properties properties) { 198 return configureLogging(logDir, properties, false); 199 } 200 201 public static String configureLogging(String logDir, Properties properties, boolean timeInFileName) { 202 return configureLogging(logDir, properties, timeInFileName, true); 203 } 204 205 /** Configurates log4j loging 206 * @param logDir output folder 207 * @param properties some other log4j properties 208 * @param timeInFileName if true log file is named debug_yyyy-MM-dd_(HH.mm.ss).log, it is named debug.log otherwise 209 */ 210 public static String configureLogging(String logDir, Properties properties, boolean timeInFileName, boolean includeSystemOuts) { 211 String time = new java.text.SimpleDateFormat( "yyyy-MM-dd_(HH.mm.ss)",java.util.Locale.US).format(new Date()); 212 (new File(logDir)).mkdirs(); 213 String fileName = logDir+File.separator+(timeInFileName?"debug_"+time:"debug")+".log"; 214 Properties props = (properties!=null?properties:new Properties()); 215 if (!props.containsKey("log4j.rootLogger")) { 216 props.setProperty("log4j.rootLogger", "debug, LogFile"); 217 if (timeInFileName) 218 props.setProperty("log4j.appender.LogFile","org.apache.log4j.FileAppender"); 219 else { 220 props.setProperty("log4j.appender.LogFile","org.apache.log4j.DailyRollingFileAppender"); 221 props.setProperty("log4j.appender.LogFile.DatePattern","'.'yyyy-MM-dd"); 222 } 223 props.setProperty("log4j.appender.LogFile.File",fileName); 224 props.setProperty("log4j.appender.LogFile.layout","org.apache.log4j.PatternLayout"); 225 props.setProperty("log4j.appender.LogFile.layout.ConversionPattern","%d{dd-MMM-yy HH:mm:ss.SSS} [%t] %-5p %c{2}> %m%n"); 226 } 227 PropertyConfigurator.configure(props); 228 Logger log = Logger.getRootLogger(); 229 log.info("-----------------------------------------------------------------------"); 230 log.info("IFS debug file"); 231 log.info(""); 232 log.info("Created: "+new Date()); 233 log.info(""); 234 log.info("System info:"); 235 log.info("System: "+System.getProperty("os.name")+" "+System.getProperty("os.version")+" "+System.getProperty("os.arch")); 236 log.info("CPU: "+System.getProperty("sun.cpu.isalist")+" endian:"+System.getProperty("sun.cpu.endian")+" encoding:"+System.getProperty("sun.io.unicode.encoding")); 237 log.info("Java: "+System.getProperty("java.vendor")+", "+System.getProperty("java.runtime.name")+" "+System.getProperty("java.runtime.version",System.getProperty("java.version"))); 238 log.info("User: "+System.getProperty("user.name")); 239 log.info("Timezone: "+System.getProperty("user.timezone")); 240 log.info("Working dir: "+System.getProperty("user.dir")); 241 log.info("Classpath: "+System.getProperty("java.class.path")); 242 log.info(""); 243 if (includeSystemOuts) { 244 System.setErr(new PrintStream(new LogOutputStream(System.err, Logger.getLogger("STDERR"),Level.ERROR))); 245 System.setOut(new PrintStream(new LogOutputStream(System.out, Logger.getLogger("STDOUT"),Level.DEBUG))); 246 } 247 return fileName; 248 } 249 250 /** Loads data properties. If there is INCLUDE property available, it is interpreted as semi-colon separated list of 251 * porperty files which should be also loaded (works recursively). 252 * 253 */ 254 public static DataProperties loadProperties(File propertyFile) { 255 FileInputStream is = null; 256 try { 257 DataProperties ret = new DataProperties(); 258 is = new FileInputStream(propertyFile); 259 ret.load(is); 260 is.close(); is=null; 261 if (ret.getProperty("INCLUDE")!=null) { 262 263 StringTokenizer stk = new StringTokenizer(ret.getProperty("INCLUDE"),";"); 264 while (stk.hasMoreTokens()) { 265 String aFile = stk.nextToken(); 266 System.out.println(" Loading included file '"+aFile+"' ... "); 267 if ((new File(aFile)).exists()) 268 is = new FileInputStream(aFile); 269 if ((new File(propertyFile.getParent()+File.separator+aFile)).exists()) 270 is = new FileInputStream(propertyFile.getParent()+File.separator+aFile); 271 if (is==null) System.err.println("Unable to find include file '"+aFile+"'."); 272 ret.load(is); 273 is.close(); is=null; 274 } 275 ret.remove("INCLUDE"); 276 } 277 return ret; 278 } catch (Exception e) { 279 System.err.println("Unable to load property file "+propertyFile); 280 e.printStackTrace(); 281 return new DataProperties(); 282 } finally { 283 try { 284 if (is!=null) is.close(); 285 } catch (IOException e) {} 286 } 287 } 288 289 public static boolean equals(Object o1, Object o2) { 290 return (o1==null?o2==null:o1.equals(o2)); 291 } 292 293 private static class LogOutputStream extends OutputStream { 294 private Logger iLogger = null; 295 private Level iLevel = null; 296 private OutputStream iOldOutputStream; 297 private ByteArrayOutputStream iOut = new ByteArrayOutputStream(); 298 public LogOutputStream(OutputStream oldOutputStream, Logger logger, Level level) { 299 iLogger = logger; 300 iLevel = level; 301 iOldOutputStream = oldOutputStream; 302 } 303 public void write(int b) throws IOException { 304 iOldOutputStream.write(b); 305 if (b=='\r') return; 306 if (b=='\n') { 307 iOut.flush(); 308 iLogger.log(iLevel, new String(iOut.toByteArray())); 309 iOut.reset(); 310 } else iOut.write(b); 311 } 312 } 313 }