package eva2.tools.math; import java.util.Arrays; import java.util.List; import eva2.server.go.tools.DoubleArrayComparator; import eva2.tools.EVAERROR; import eva2.tools.math.Jama.Matrix; import eva2.tools.math.interpolation.BasicDataSet; import eva2.tools.math.interpolation.InterpolationException; import eva2.tools.math.interpolation.SplineInterpolation; //created at June 27 2006 /** * @author Andreas Dräger */ public class Mathematics { public static void revertArray(Object[] src, Object[] dst) { if (dst.length>=src.length) { for (int i=0; i dblArrList, boolean interpolate) { java.util.Collections.sort(dblArrList, new DoubleArrayComparator()); int len = dblArrList.size(); if (len % 2 != 0) return dblArrList.get((len-1) / 2); else { double[] med = dblArrList.get(len/2).clone(); if (interpolate) { vvAdd(med, dblArrList.get((len/2)+1), med); svDiv(2, med, med); } return med; } } /** * This method gives a linear interpolation of the function values of the * given argument/function value pairs. * * @param x * The argument at the point with unknown function value * @param x0 * The argument at the last position with a function value * @param x1 * The argument at the next known fuction value * @param f0 * The function value at the position x0 * @param f1 * The function value at the position x1 * @return The function value at position x given by linear interpolation. */ public static double linearInterpolation(double x, double x0, double x1, double f0, double f1) { if (x1 == x0) return f0; return lerp(f0, f1, (x - x0) / (x1 - x0)); } /** * Computes a hyperbolic interpolation of the two point (x0,f0) and (x1,f1). * * @param x * @param x0 * @param x1 * @param f0 * @param f1 * @return */ public static double hyperbolicInterpolation(double x, double x0, double x1, double f0, double f1) { if (x1 == 0) return lerp(f0, f1, (x - x0) / (-x0)); double l = lerp(x0 / x1, 1, x); if (l == 0) return linearInterpolation(x, x0, x1, f0, f1); return lerp(f0, f1, x / l); } // <<<<<<< .working // /** // * Computes a spline interpolation of the two point (x0,f0) and (x1,f1). // * // * @param x // * @param x0 // * @param x1 // * @param f0 // * @param f1 // * @return If an error with the spline occurs, a linear interpolation will be // * returned. // */ // /* public static double splineInterpolation(double x, double x0, double x1, // double f0, double f1) { // try { // double[] t = { x0, x1 }, f = { f0, f1 }; // SplineInterpolation spline = new SplineInterpolation(new BasicDataSet(t, // f, 1)); // return spline.getY(x); // } catch (InterpolationException e) { // e.printStackTrace(); // } // return linearInterpolation(x, x0, x1, f0, f1); // }*/ // ======= /** * Computes a spline interpolation of the two point (x0,f0) and (x1,f1). * * @param x * @param x0 * @param x1 * @param f0 * @param f1 * @return If an error with the spline occurs, a linear interpolation will be * returned. */ public static double splineInterpolation(double x, double x0, double x1, double f0, double f1) { try { double[] t = {x0, x1}, f = {f0, f1}; SplineInterpolation spline = new SplineInterpolation(new BasicDataSet(t, f, 1)); return spline.getY(x); } catch (InterpolationException e) { e.printStackTrace(); } return linearInterpolation(x, x0, x1, f0, f1); } /** * @param f0 * @param f1 * @param t * @return */ private static double lerp(double f0, double f1, double t) { return f0 + (f1 - f0) * t; } /** * Computes the root-Distance function. For example root = 2 gives the * Euclidian Distance. * * @param x * a vector * @param y * another vector * @param root * what kind of distance funktion * @return the distance of x and y * @throws Exception * if x and y have different dimensions an exception is * thrown. */ public static double dist(double[] x, double[] y, int root) { if (x.length != y.length) throw new RuntimeException("The vectors x and y must have the same dimension"); if (root == 0) throw new RuntimeException("There is no 0-root!"); double d = 0; for (int i = 0; i < x.length; i++) d += Math.pow(Math.abs(x[i] - y[i]), root); return Math.pow(d, (double) 1 / root); } /** * Computes the euclidian distance function. * * @param x * a vector * @param y * another vector * @param root * what kind of distance funktion * @return the distance of x and y * @throws Exception * if x and y have different dimensions an exception is * thrown. */ public static double euclidianDist(double[] x, double[] y) { if (x.length != y.length) throw new RuntimeException("The vectors x and y must have the same dimension"); double d = 0; for (int i = 0; i < x.length; i++) d += Math.pow(Math.abs(x[i] - y[i]), 2); return Math.sqrt(d); } /** * Computes the relative distance of vector x to vector y. Therefore the * difference of x[i] and y[i] is divided by y[i] for every i. If y[i] is * zero, the default value def is used instead. The sum of these differences * gives the distance function. * * @param x * A vector * @param y * The reference vector * @param def * The default value to be use to avoid division by zero. * @return The relative distance of x to y. * @throws Exception */ public static double relDist(double[] x, double[] y, double def) throws Exception { if (x.length != y.length) throw new Exception("The vectors x and y must have the same dimension"); double d = 0; for (int i = 0; i < x.length; i++) if (y[i] != 0) d += Math.pow(((x[i] - y[i]) / y[i]), 2); else d += def; return d; } /** * This computes the determinant of the given matrix * * @param matrix * @return The determinant or null if there is no determinant (if the matrix * is not square). */ public static double determinant(double[][] matrix) { if (matrix == null) return 0; if (matrix.length != matrix[0].length) return 0; if (matrix.length == 1) return matrix[0][0]; if (matrix.length == 2) return matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0]; if (matrix.length == 3) return matrix[0][0] * matrix[1][1] * matrix[2][2] + matrix[0][1] * matrix[1][2] * matrix[2][0] + matrix[0][2] * matrix[1][0] * matrix[2][1] - matrix[2][0] * matrix[1][1] * matrix[0][2] - matrix[2][1] * matrix[1][2] * matrix[0][0] - matrix[2][2] * matrix[1][0] * matrix[0][1]; double det = 0; for (int k = 0; k < matrix.length; k++) { if (matrix[0][k] != 0) det += matrix[0][k] * adjoint(matrix, 0, k); } return det; } /** * This computes the submatrix of the given matrix as a result by scraching * out the row k and the column l. * * @param a * @param k * @param l * @return */ public static double[][] submatrix(double[][] a, int k, int l) { double b[][] = new double[a.length - 1][a[0].length - 1]; int i, j, m = 0, n = 0; for (i = 0; i < a.length; i++) { if (i == k) continue; for (j = 0; j < a[0].length; j++) { if (j == l) continue; b[m][n++] = a[i][j]; } m++; n = 0; } return b; } /** * Computes the adjoint of the matrix element at the position (k, l). * * @param a * @param k * @param l * @return */ public static double adjoint(double[][] a, int k, int l) { return Math.pow(-1, k + l + 2) * determinant(submatrix(a, k, l)); } /** * Computes the full adjoint matrix. * * @param a * @return */ public static double[][] adjoint(double[][] a) { if (a == null) return null; if (a.length != a[0].length) return null; double[][] b = new double[a.length][a.length]; for (int i = 0; i < a.length; i++) for (int j = 0; j < a.length; j++) b[i][j] = adjoint(a, i, j); return b; } /** * Computes the inverse of the given matrix or returns null if there is no * inverse (if the determinant is 0). * * @param a * @return */ public static double[][] inverse(double[][] a) { if (a == null) return null; if (a.length != a[0].length) return null; double det = determinant(a); if (det == 0) return null; double[][] b = adjoint(a); for (int i = 0; i < a.length; i++) for (int j = 0; j < a.length; j++) b[i][j] /= det; return b; } /** This method returns a mean vector from a whole array of vectors. * @param d d[i] the vectors, d[i][j] the jth coordinate of the ith vector * @return The mean vector. */ public static double[] meanVect(double[][] d) { double[] result = new double[d[0].length]; for (int i = 0; i < d.length; i++) { for (int j = 0; j < d[i].length; j++) { result[j] += d[i][j]; } } for (int i = 0; i < result.length; i++) { result[i] = result[i]/((double)d.length); } return result; } /** * Subtract vectors returning a new vector c = a - b. * * @param a * @param b * @return a new vector c = a - b */ public static double[] vvSub(double[] a, double[] b) { double[] result = new double[a.length]; vvSub(a, b, result); return result; } /** * Subtract vectors returning a new vector c = a - b. * * @param a * @param b * @return a new vector c = a - b */ public static void vvSub(double[] a, double[] b, double[] res) { for (int i = 0; i < a.length; i++) { res[i] = a[i] - b[i]; } } /** * This method return a vector from a to b * @param a first vector * @param b second vectors * @return the vector from a to b */ public static double[] getVectorFromTo(double[] a, double[] b) { return vvSub(b,a); } /** * Add vectors returning a new vector c = a + b; * @param a * @param b * @return a new vector c = a + b */ public static double[] vvAdd(double[] a, double[] b) { double[] result = new double[a.length]; for (int i = 0; i < a.length; i++) { result[i] = a[i] + b[i]; } return result; } /** * Add vectors in place setting res = v1 + v2. * * @param v1 * @param v2 * @return vector addition */ public static void vvAdd(double[] v1, double[] v2, double[] res) { vvAddOffs(v1, 0, v2, 0, res, 0, v1.length); } /** * Add vectors in place setting with an offset within the target * vector, meaning that res[resOffs+i]=v1[v1Offs+i]+v2[v2Offs+i] for i in length. * * @param v1 * @param v2 * @return vector addition */ public static void vvAddOffs(double[] v1, int v1Offs, double[] v2, int v2Offs, double[] res, int resOffs, int len) { for (int i = 0; i < len; i++) res[resOffs+i] = v1[v1Offs+i] + v2[v2Offs+i]; } /** * Add each entry of a vector with a scalar in a new vector. * * @param s * @param v * @return */ public static double[] svAdd (double s, double[] v) { double[] res = new double[v.length]; svAdd(s, v, res); return res; } /** * Add each entry of a vector with a scalar in a result vector. * * @param s * @param v * @return */ public static void svAdd(double s, double[] v, double[] res) { for (int i = 0; i < v.length; i++) { res[i] = v[i] + s; } } /** * Add vectors scaled: res[i] = s*v[i] + w[i] * * @param s * @param v * @param w * @return */ public static void svvAddScaled(double s, double[] v, double[] w, double[] res) { for (int i = 0; i < v.length; i++) { res[i] = s*v[i] + w[i]; } } /** * Scalar product of two vectors returning sum_i (a_i * b_i). * * @param a * @param b * @return */ public static double vvMult(double[] a, double[] b) { double result = 0; for (int i = 0; i < a.length; i++) { result += a[i]*b[i]; } return result; } /** * Multiplies (scales) every element of the array v with s returning a new vector. * * @param s * a scalar * @param v * an array to be multiplied with s. * @return a scaled array. */ public static double[] svMult(double s, double[] v) { double[] res = new double[v.length]; for (int i = 0; i < v.length; i++) { res[i] = v[i] * s; } return res; } /** * Multiplies (scales) every element of the array v with s in place. * * @param s a scalar * @param v an array to be multiplied with s. * @return a scaled array. */ public static void svMult(double s, double[] v, double[] res) { for (int i = 0; i < v.length; i++) { res[i] = v[i] * s; } } /** * Return a new vector which is c = (v_i/s). * * @param s * @param v * @return */ public static double[] svDiv(double s, double[] v) { double[] res = new double[v.length]; for (int i = 0; i < v.length; i++) { res[i] = v[i] / s; } return res; } /** * Divide by scalar in place, res_i = v_i/s. * * @param s * @param v * @return */ public static void svDiv(double s, double[] v, double[] res) { for (int i = 0; i < v.length; i++) { res[i] = v[i] / s; } } /** * Component wise multiplication of vectors: res[i]=u[i]*v[i] * * @param s * @param v * @return */ public static void vvMultCw(double[] u, double[] v, double[] res) { for (int i = 0; i < res.length; i++) { res[i] = u[i]*v[i]; } } /** * Return a vector of given length containing zeroes. * @param n * @return */ public static double[] zeroes(int n) { double[] result = new double[n]; Arrays.fill(result, 0, result.length-1, 0.); return result; } /** * Returns false if a vector contains NaN, its squared sum is NaN * or the absolute sum is smaller than 10^-18. * @param d * @return */ public static boolean isValidVec(double[] d) { double sum = 0; for (int i = 0; i < d.length; i++) { if (Double.isNaN(d[i])) return false; sum += Math.pow(d[i],2); } if (Double.isNaN(sum)) return false; if (Math.abs(sum) < 0.000000000000000001) return false; return true; } /** * Computes the sum of the elements of an array of doubles. * * @param doubles the array of double * @return the sum of the elements */ public static double sum(double[] doubles) { double sum = 0; for (int i = 0; i < doubles.length; i++) { sum += doubles[i]; } return sum; } /** * Computes the mean for an array of doubles. * * @param vector the array * @return the mean */ public static double mean(double[] vector) { if (vector.length == 0) { return 0; } return sum(vector) / (double)vector.length; } // /** // * Normalizes the doubles in the array using the given value so that they sum up to 1. // * // * @param doubles the array of double // * @param sum the value by which the doubles are to be normalized // * @exception IllegalArgumentException if sum is zero or NaN // */ // public static void normalize(double[] v, double sum, double[] res) { // if (Double.isNaN(sum)) { // throw new IllegalArgumentException("Can't normalize array. Sum is NaN."); // } // if (sum == 0) { // // Maybe this should just be a return. // throw new IllegalArgumentException("Can't normalize array. Sum is zero."); // } // svMult(1/sum, v, res); // } /** * Computes the sum of the elements of an array of integers. * * @param ints the array of integers * @return the sum of the elements */ public static int sum(int[] ints) { int sum = 0; for (int i = 0; i < ints.length; i++) { sum += ints[i]; } return sum; } /** * Computes the 2-norm of an array of doubles. * * @param doubles the array of double * @return the 2-norm of the elements */ public static double norm(double[] d) { double sqSum = 0; for (int i = 0; i < d.length; i++) { sqSum += d[i]*d[i]; } return Math.sqrt(sqSum); } /** * Normalize the given vector to an euclidian length of 1. * * @param v * @return */ public static double[] normVect(double[] v) { return svDiv(norm(v), v); } /** * Normalize the given vector to an euclidian length of 1. * * @param v * @return */ public static void normVect(double[] v, double[] res) { svDiv(norm(v), v, res); } /** * Calculates the norm of the given vector relative to the problem range. * * @param vector a double vector within the range * @param range the range in each dimension * @return measure of the length relative to the problem range */ public static double getRelativeLength(double[] vector, double[][] range) { double sumV = 0; double sumR = 0; for (int i = 0; i < range.length; i++) { sumV += Math.pow(vector[i], 2); sumR += Math.pow(range[i][1] - range[i][0], 2); } sumV = Math.sqrt(sumV); sumR = Math.sqrt(sumR); return sumV/sumR; } /** * Create a random vector, the components will be set to gaussian distributed * values with mean zero and the given standard deviation. * * @param dim the desired dimension * @param stdDev the gaussian standard deviation * @return random vector */ public static double[] randomVector(int dim, double stdDev) { double[] vect = new double[dim]; for (int j = 0; j < vect.length; j++) { vect[j] = RNG.gaussianDouble(stdDev); } return vect; } /** * Normalizes the doubles in the array by their sum, * so that they add up to one. * @param doubles the array of double * @exception IllegalArgumentException if sum is Zero or NaN */ public static double[] normalizeSum(double[] v) { double[] res = new double[v.length]; svMult(1./sum(v), v,res); return res; } /** * Normalizes the doubles in the array by their sum, * so that they add up to one. * * @param doubles the array of double * @exception IllegalArgumentException if sum is Zero or NaN */ public static void normalizeSum(double[] v, double[] res) { svMult(1./sum(v), v, res); } /** * Return a matrix A which performs the rotation of vec to (1,0,0,...0) if forward is true, else * return a matrix B which performs the reverted rotation, where B=A' (transposition). * * @param vec * @return */ public static Matrix getRotationMatrix(Matrix vec) { Matrix A = Matrix.identity(vec.getRowDimension(), vec.getRowDimension()); Matrix tmp = Matrix.identity(vec.getRowDimension(), vec.getRowDimension()); Matrix z = (Matrix)vec.clone(); double w, cosw, sinw; z.multi(z.norm2()); // normalize for (int i=1; irange[i][1])) return false; } return true; } /** * Check whether the given value lies within the interval in every dimension. * * @param x * @param range * @return true if the vector lies within the range, else false */ public static boolean isInRange(double v, double lower, double upper) { if (vupper)) return false; return true; } /** * Return the vector of interval length values in any dimension. * ret[i]=range[i][1]-range[i][0]; * * @param range * @return */ public static double[] getAbsRange(double[][] range) { double[] ret = new double[range.length]; for (int i = 0; i < ret.length; i++) { ret[i]=range[i][1]-range[i][0]; } return ret; } /** * Shift bounds by a constant value in every dimension. * * @param range * @return */ public static void shiftRange(double[][] range, double dist) { for (int i = 0; i < range.length; i++) { svAdd(dist, range[i]); } } /** * Shift bounds by a constant value in every dimension. The dists * must be of dimensions as the range. * * @param range * @return */ public static void shiftRange(double[][] range, double[] dists) { for (int i = 0; i < range.length; i++) { svAdd(dists[i], range[i]); } } /** * Project the values in x to the range given. The range must be an vector of 2d-arrays * each of which containing lower and upper bound in the i-th dimension. * x must not be longer than the available ranges. * Values exceeding the bounds are set on the bound. * The number of bound violations is returned. * * @param x * @param range * @return */ public static int projectToRange(double[] x, double[][] range) { int viols = 0; if (x.length>range.length) System.err.println("Invalid vector length, x is longer than range! (Mathematics.projectToRange)"); for (int i=0; irange[i][1]) { viols++; x[i]=range[i][1]; } } return viols; } /** * Scale a range by the given factor, meaning that the interval in each dimension is * extended (fact>1) or reduced (fact<1) by the defined ratio around the center. * * @param rangeScaleFact * @param range */ public static void scaleRange(double rangeScaleFact, double[][] range) { double[] intervalLengths=Mathematics.getAbsRange(range); double[] tmpInts=Mathematics.svMult(rangeScaleFact, intervalLengths); Mathematics.vvSub(tmpInts, intervalLengths, tmpInts); // this is what must be added to range interval for (int i=0; imax) { return max; } else return v; } /** * Calculate the average length of the range intervals over all dimensions. * * @param range * @return the average length of the range intervals */ public static double getAvgRange(double[][] range) { double sum = 0.; for (int i=0; i dimLen) d -= dimLen; // avoid violating the other bound immediately x[i]=range[i][0]+d; } else if (x[i]>range[i][1]) { viols++; d = x[i]-range[i][1]; while (d>dimLen) d -= dimLen; // avoid violating the other bound immediately x[i]=range[i][1]-d; } } return viols; } /** * Simple version of reflection of a value moving by a step and bouncing * of min and max values like a pool ball. Precondition is min <= val <= max, * post condition is min <= retVal <= max. * * @param val * @param step * @param min * @param max * @return */ public static double reflectValue(double val, double step, double min, double max) { while (step > (max-min)) step -= (max-min); if ((val + step) > max) return (2 * max - val - step); if ((val + step) < min) return (2 * min - val - step); return (val += step); } /** * Return first multiple of interval which is larger than len. * * @param len * @param interval * @return */ public static double firstMultipleAbove(double len, double interval) { double startVal,dn = (len / interval ); startVal = Math.round(dn-0.5)*interval; if( startVal < len || (len==0)) { startVal+=interval; } return startVal; } /** * Return the product over a double vector. * @param vals * @return */ public static double product(double[] vals) { double prod=1.; for (int i = 0; i < vals.length; i++) { prod*=vals[i]; } return prod; } /** * Intersect two ranges resulting in the maximum range contained in both. * * @param modRange * @param makeRange * @param destRange */ public static void intersectRange(double[][] r1, double[][] r2, double[][] destRange) { for (int i=0; i