/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.EOFException; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; import java.util.Properties; import org.apache.commons.math4.stat.descriptive.SummaryStatistics; import org.apache.commons.math4.util.FastMath; /* * plot 'logGamma.dat' binary format="%double%double" endian=big u 1:2 w l */ public class RealFunctionValidation { public static class MissingRequiredPropertyException extends IllegalArgumentException { private static final long serialVersionUID = 20121017L; public MissingRequiredPropertyException(final String key) { super("missing required property " + key); } } public static class ApplicationProperties { private static final int DOT = '.'; private static final String METHOD_KEY = "method"; private static final String SIGNATURE_KEY = "signature"; private static final String INPUT_FILE_MASK = "inputFileMask"; private static final String OUTPUT_FILE_MASK = "outputFileMask"; private static final String FROM_KEY = "from"; private static final String TO_KEY = "to"; private static final String BY_KEY = "by"; final Method method; final String inputFileMask; final String outputFileMask; final int from; final int to; final int by; /** * Returns a {@link Method} with specified signature. * * @param className The fully qualified name of the class to which the * method belongs. * @param methodName The name of the method. * @param signature The signature of the method, as a list of parameter * types. * @return the method * @throws SecurityException * @throws ClassNotFoundException */ public static Method findStaticMethod(final String className, final String methodName, final List<Class<?>> signature) throws SecurityException, ClassNotFoundException { final int n = signature.size(); final Method[] methods = Class.forName(className).getMethods(); for (Method method : methods) { if (method.getName().equals(methodName)) { final Class<?>[] parameters = method.getParameterTypes(); boolean sameSignature = true; if (parameters.length == n) { for (int i = 0; i < n; i++) { sameSignature &= signature.get(i) .equals(parameters[i]); } if (sameSignature) { final int modifiers = method.getModifiers(); if ((modifiers & Modifier.STATIC) != 0) { return method; } else { final String msg = "method must be static"; throw new IllegalArgumentException(msg); } } } } } throw new IllegalArgumentException("method not found"); } public static Class<?> parsePrimitiveType(final String type) { if (type.equals("boolean")) { return Boolean.TYPE; } else if (type.equals("byte")) { return Byte.TYPE; } else if (type.equals("char")) { return Character.TYPE; } else if (type.equals("double")) { return Double.TYPE; } else if (type.equals("float")) { return Float.TYPE; } else if (type.equals("int")) { return Integer.TYPE; } else if (type.equals("long")) { return Long.TYPE; } else if (type.equals("short")) { return Short.TYPE; } else { final StringBuilder builder = new StringBuilder(); builder.append(type).append(" is not a primitive type"); throw new IllegalArgumentException(builder.toString()); } } private static String getPropertyAsString(final Properties properties, final String key) { final String value = properties.getProperty(key); if (value == null) { throw new MissingRequiredPropertyException(key); } else { return value; } } private static int getPropertyAsInteger(final Properties properties, final String key) { final String value = properties.getProperty(key); if (value == null) { throw new MissingRequiredPropertyException(key); } else { return Integer.parseInt(value); } } private ApplicationProperties(final String fullyQualifiedName, final String signature, final String inputFileMask, final String outputFileMask, final int from, final int to, final int by) { this.inputFileMask = inputFileMask; this.outputFileMask = outputFileMask; this.from = from; this.to = to; this.by = by; final String[] types = signature.split(","); final List<Class<?>> parameterTypes = new ArrayList<Class<?>>(); for (String type : types) { parameterTypes.add(parsePrimitiveType(type.trim())); } final int index = fullyQualifiedName.lastIndexOf(DOT); try { final String className, methodName; className = fullyQualifiedName.substring(0, index); methodName = fullyQualifiedName.substring(index + 1); this.method = findStaticMethod(className, methodName, parameterTypes); } catch (ClassNotFoundException e) { throw new IllegalArgumentException(e); } } public static final ApplicationProperties create(final Properties properties) { final String methodFullyQualifiedName; methodFullyQualifiedName = getPropertyAsString(properties, METHOD_KEY); final String signature; signature = getPropertyAsString(properties, SIGNATURE_KEY); final String inputFileMask; inputFileMask = getPropertyAsString(properties, INPUT_FILE_MASK); final String outputFileMask; outputFileMask = getPropertyAsString(properties, OUTPUT_FILE_MASK); final int from = getPropertyAsInteger(properties, FROM_KEY); final int to = getPropertyAsInteger(properties, TO_KEY); final int by = getPropertyAsInteger(properties, BY_KEY); return new ApplicationProperties(methodFullyQualifiedName, signature, inputFileMask, outputFileMask, from, to, by); } }; public static Object readAndWritePrimitiveValue(final DataInputStream in, final DataOutputStream out, final Class<?> type) throws IOException { if (!type.isPrimitive()) { throw new IllegalArgumentException("type must be primitive"); } if (type.equals(Boolean.TYPE)) { final boolean x = in.readBoolean(); out.writeBoolean(x); return Boolean.valueOf(x); } else if (type.equals(Byte.TYPE)) { final byte x = in.readByte(); out.writeByte(x); return Byte.valueOf(x); } else if (type.equals(Character.TYPE)) { final char x = in.readChar(); out.writeChar(x); return Character.valueOf(x); } else if (type.equals(Double.TYPE)) { final double x = in.readDouble(); out.writeDouble(x); return Double.valueOf(x); } else if (type.equals(Float.TYPE)) { final float x = in.readFloat(); out.writeFloat(x); return Float.valueOf(x); } else if (type.equals(Integer.TYPE)) { final int x = in.readInt(); out.writeInt(x); return Integer.valueOf(x); } else if (type.equals(Long.TYPE)) { final long x = in.readLong(); out.writeLong(x); return Long.valueOf(x); } else if (type.equals(Short.TYPE)) { final short x = in.readShort(); out.writeShort(x); return Short.valueOf(x); } else { // This should never occur. throw new IllegalStateException(); } } public static SummaryStatistics assessAccuracy(final Method method, final DataInputStream in, final DataOutputStream out) throws IOException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (method.getReturnType() != Double.TYPE) { throw new IllegalArgumentException("method must return a double"); } final Class<?>[] types = method.getParameterTypes(); for (int i = 0; i < types.length; i++) { if (!types[i].isPrimitive()) { final StringBuilder builder = new StringBuilder(); builder.append("argument #").append(i + 1) .append(" of method ").append(method.getName()) .append("must be of primitive of type"); throw new IllegalArgumentException(builder.toString()); } } final SummaryStatistics stat = new SummaryStatistics(); final Object[] parameters = new Object[types.length]; while (true) { try { for (int i = 0; i < parameters.length; i++) { parameters[i] = readAndWritePrimitiveValue(in, out, types[i]); } final double expected = in.readDouble(); if (FastMath.abs(expected) > 1E-16) { final Object value = method.invoke(null, parameters); final double actual = ((Double) value).doubleValue(); final double err = FastMath.abs(actual - expected); final double ulps = err / FastMath.ulp(expected); out.writeDouble(expected); out.writeDouble(actual); out.writeDouble(ulps); stat.addValue(ulps); } } catch (EOFException e) { break; } } return stat; } public static void run(final ApplicationProperties properties) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException { for (int i = properties.from; i < properties.to; i += properties.by) { final String inputFileName; inputFileName = String.format(properties.inputFileMask, i); final String outputFileName; outputFileName = String.format(properties.outputFileMask, i); final DataInputStream in; in = new DataInputStream(new FileInputStream(inputFileName)); final DataOutputStream out; out = new DataOutputStream(new FileOutputStream(outputFileName)); final SummaryStatistics stats; stats = assessAccuracy(properties.method, in, out); System.out.println("input file name = " + inputFileName); System.out.println("output file name = " + outputFileName); System.out.println(stats); } } public static void main(final String[] args) throws IOException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (args.length == 0) { final String msg = "missing required properties file"; throw new IllegalArgumentException(msg); } final FileInputStream in = new FileInputStream(args[0]); final Properties properties = new Properties(); properties.load(in); in.close(); final ApplicationProperties p; p = ApplicationProperties.create(properties); run(p); } }