Small java application for the accuracy assessment of implementations of real
functions in Commons Math. The accuracy is assessed through comparison with reference values computed with multi-precision softwares. git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1407376 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
37791912c6
commit
b04b10ca6e
|
@ -0,0 +1 @@
|
||||||
|
Main-Class: RealFunctionValidation
|
|
@ -0,0 +1,139 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Validation of real functions
|
||||||
|
============================
|
||||||
|
|
||||||
|
This document details the procedure used in Commons-Math 3 to assess the
|
||||||
|
accuracy of the implementations of special functions. It is a two-step process
|
||||||
|
|
||||||
|
1. reference values are computed with a multi-precision software (for example,
|
||||||
|
the Maxima Computer Algebra System) [1],
|
||||||
|
2. these reference values are compared with the Commons-Math3 implementation.
|
||||||
|
The accuracy is computed in ulps.
|
||||||
|
|
||||||
|
This process relies on a small Java application, called RealFunctionValidation,
|
||||||
|
which can be found in $CM3_SRC/src/test/maxima/special, where $CM3_SRC is the
|
||||||
|
root directory to the source of Commons-Math 3
|
||||||
|
|
||||||
|
|
||||||
|
Compilation of RealFunctionValidation
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
Change to the relevant directory
|
||||||
|
|
||||||
|
cd $CM3_SRC/src/test/maxima/special/RealFunctionValidation
|
||||||
|
|
||||||
|
Compile the source file. The jar file of Commons-Math3 should be included in
|
||||||
|
your classpath. If it is installed in your local maven repository, the
|
||||||
|
following command should work
|
||||||
|
|
||||||
|
javac -classpath $HOME/.m2/repository/org/apache/commons/commons-math3/3.1-SNAPSHOT/commons-math3-3.1-SNAPSHOT.jar RealFunctionValidation.java
|
||||||
|
|
||||||
|
Create a jar file
|
||||||
|
|
||||||
|
jar cfm RealFunctionValidation.jar Manifest.txt RealFunctionValidation*.class
|
||||||
|
|
||||||
|
Remove the unused *.class files
|
||||||
|
|
||||||
|
rm *.class
|
||||||
|
|
||||||
|
|
||||||
|
Invocation of the application RealFunctionValidation
|
||||||
|
----------------------------------------------------
|
||||||
|
|
||||||
|
The java application comes with a shell script, RealFunctionValidaton.sh. You
|
||||||
|
should edit this file, and change the variables
|
||||||
|
- CM3_JAR: full path to the Commons-Math 3 jar file,
|
||||||
|
- APP_JAR: full path to the RealFunctionValidation application jar file.
|
||||||
|
|
||||||
|
Invoking this application is then very simple. For example, to validate the
|
||||||
|
implementation of Gamma.logGamma, change to directory reference
|
||||||
|
|
||||||
|
cd $CM3_SRC/src/test/maxima/special/reference
|
||||||
|
|
||||||
|
and run the application
|
||||||
|
|
||||||
|
../RealFunctionValidation/RealFunctionValidation.sh logGamma.properties
|
||||||
|
|
||||||
|
|
||||||
|
Syntax of the *.properties files
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
Parameters of the RealFunctionValidation application are specified through a
|
||||||
|
standard Java properties file. The following keys must be specified in this
|
||||||
|
file
|
||||||
|
|
||||||
|
- method: the fully qualified name to the function to be validated. This
|
||||||
|
function should be static, take only primitive arguments, and return double.
|
||||||
|
- signature: this key is necessary to discriminate functions with same name.
|
||||||
|
The signature should be specified as in a plain java file. For example
|
||||||
|
signature = double, int, float
|
||||||
|
- inputFileMask: the name of the binary input file(s) containing the
|
||||||
|
high-accuracy reference values. The format of this file is described in
|
||||||
|
the next section. It is possible to specify multiple input files, which are
|
||||||
|
indexed by an integer. Then this key should really be understood as a format
|
||||||
|
string. In other words, the name of the file with index i is given by
|
||||||
|
String.format(inputFileMask, i)
|
||||||
|
- outputFileMask: the name of the binary output file(s) containing the
|
||||||
|
reference values, the values computed through the specified method, and
|
||||||
|
the error (in ulps). The format of this file is described in the next section. As for the input files, it is possible to specify multiple output files.
|
||||||
|
- from: the first index
|
||||||
|
- to: the last index (exclusive)
|
||||||
|
- by: the increment
|
||||||
|
|
||||||
|
As an example, here is the properties file for evaluation of
|
||||||
|
double Gamma.logGamma(double)
|
||||||
|
|
||||||
|
method=org.apache.commons.math3.special.Gamma.logGamma
|
||||||
|
signature=double
|
||||||
|
inputFileMask=logGamma-%02d.dat
|
||||||
|
outputFileMask=logGamma-out-%02d.dat
|
||||||
|
from=1
|
||||||
|
to=5
|
||||||
|
by=1
|
||||||
|
|
||||||
|
Format of the input and output binary files
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
The reference values are saved in a binary file
|
||||||
|
- for a unary function f(x), the data is stored as follows
|
||||||
|
x[0], f(x[0]), x[1], f(x[1]), ...
|
||||||
|
- for a binary function f(x, y), the data is stored as follows
|
||||||
|
x[0], y[0], f(x[0], y[0]), x[1], y[1], f(x[1], y[1]), ...
|
||||||
|
- and similar storage pattern for a n-ary function.
|
||||||
|
|
||||||
|
The parameters x[i], y[i], ... can be of arbitrary (primitive) type. The return
|
||||||
|
value f(x[i], y[i], ...) must be of type double.
|
||||||
|
|
||||||
|
The output files are also saved in a binary file
|
||||||
|
- for a unary function f(x), the data is stored as follows
|
||||||
|
x[0], reference value of f(x[0]), actual value of f(x[0], y[0]),
|
||||||
|
error in ulps, x[1], y[1], reference value of f(x[1], y[1]), actual value of
|
||||||
|
f(x[1], y[1]), error in ulps, ...
|
||||||
|
- for a binary function f(x, y), the data is stored as follows
|
||||||
|
x[0], y[0], reference value of f(x[0], y[0]), actual value of f(x[0], y[0]),
|
||||||
|
error in ulps, x[1], y[1], reference value of f(x[1], y[1]), actual value of
|
||||||
|
f(x[1], y[1]), error in ulps, ...
|
||||||
|
|
||||||
|
The application also prints on the standard output some statistics about the
|
||||||
|
error.
|
||||||
|
|
||||||
|
References
|
||||||
|
----------
|
||||||
|
|
||||||
|
[1] http://maxima.sourceforge.net/
|
|
@ -0,0 +1,361 @@
|
||||||
|
/*
|
||||||
|
* 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.math3.stat.descriptive.SummaryStatistics;
|
||||||
|
import org.apache.commons.math3.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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Location of the Commons-Math3 jar file
|
||||||
|
CM3_JAR=$HOME/.m2/repository/org/apache/commons/commons-math3/3.1-SNAPSHOT/commons-math3-3.1-SNAPSHOT.jar
|
||||||
|
|
||||||
|
# Location of file RealFunctionValidation.jar
|
||||||
|
APP_JAR=$HOME/Documents/workspace/commons-math3/src/test/maxima/special/RealFunctionValidation/RealFunctionValidation.jar
|
||||||
|
|
||||||
|
java -cp $CM3_JAR:$APP_JAR RealFunctionValidation logGamma.properties
|
Loading…
Reference in New Issue