/* * RapidMiner * * Copyright (C) 2001-2008 by Rapid-I and the contributors * * Complete list of developers available at our web site: * * http://rapid-i.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see http://www.gnu.org/licenses/. */ package com.rapidminer.tools.math; /** * This class provides mathematical functions not already provided by * <tt>java.lang.Math</tt>: * <ul> * <li><tt>tanh()</tt> : tangens hyperbolicus, <i>y = tanh(x) = (e^x - e^-x) / * (e^x + e^-x)</i></li> * </ul> * * @author Ralf Klinkenberg * @version $Id: MathFunctions.java,v 1.6 2008/05/09 19:23:03 ingomierswa Exp $ */ public class MathFunctions { protected static final double log2 = Math.log(2.0d); /** * coefficients for polynomials used in normalInverse() to estimate normal * distribution; */ // coefficients for approximation of intervall 0,138... < probability < // 0,861... protected static final double DIVISOR_COEFFICIENTS_0[] = { -5.99633501014107895267E1, 9.80010754185999661536E1, -5.66762857469070293439E1, 1.39312609387279679503E1, -1.23916583867381258016E0, }; protected static final double DIVIDER_COEFFICIENTS_0[] = { 1.00000000000000000000E0, 1.95448858338141759834E0, 4.67627912898881538453E0, 8.63602421390890590575E1, -2.25462687854119370527E2, 2.00260212380060660359E2, -8.20372256168333339912E1, 1.59056225126211695515E1, -1.18331621121330003142E0, }; // coefficients for approximation of intervall exp(-32) < probability < // 0,138... // or 0,861 < probability < 1 - exp(-32) protected static final double DIVISOR_COEFFICIENTS_1[] = { 4.05544892305962419923E0, 3.15251094599893866154E1, 5.71628192246421288162E1, 4.40805073893200834700E1, 1.46849561928858024014E1, 2.18663306850790267539E0, -1.40256079171354495875E-1, -3.50424626827848203418E-2, -8.57456785154685413611E-4, }; protected static final double DIVIDER_COEFFICIENTS_1[] = { 1.00000000000000000000E0, 1.57799883256466749731E1, 4.53907635128879210584E1, 4.13172038254672030440E1, 1.50425385692907503408E1, 2.50464946208309415979E0, -1.42182922854787788574E-1, -3.80806407691578277194E-2, -9.33259480895457427372E-4, }; // coefficients for approximation of intervall 0 < probability < exp(-32) // or 1 - exp(-32) < probability < 1 protected static final double DIVISOR_COEFFICIENTS_3[] = { 3.23774891776946035970E0, 6.91522889068984211695E0, 3.93881025292474443415E0, 1.33303460815807542389E0, 2.01485389549179081538E-1, 1.23716634817820021358E-2, 3.01581553508235416007E-4, 2.65806974686737550832E-6, 6.23974539184983293730E-9, }; protected static final double DIVIDER_COEFFICIENTS_3[] = { 1.00000000000000000000E0, 6.02427039364742014255E0, 3.67983563856160859403E0, 1.37702099489081330271E0, 2.16236993594496635890E-1, 1.34204006088543189037E-2, 3.28014464682127739104E-4, 2.89247864745380683936E-6, 6.79019408009981274425E-9, }; /** * returns tangens hyperbolicus of <tt>x</tt>, i.e. <i>y = tanh(x) = (e^x - * e^-x) / (e^x + e^-x)</i>. */ public static double tanh(double x) { return ((java.lang.Math.exp(x) - java.lang.Math.exp(-x)) / (java.lang.Math .exp(x) + java.lang.Math.exp(-x))); } /** * Returns the value x for which the area under the normal probability * density function (integrated from minus infinity to this value x) is * equal to the given probability. The normal distribution has mean of zero * and variance of one. * * @param probability * the area under the normal pdf * @return x */ public static double normalInverse(double probability) { final double smallArgumentEnd = Math.exp(-2); final double rootedPi = Math.sqrt(2.0 * Math.PI); if (probability <= 0.0) throw new IllegalArgumentException(); if (probability >= 1.0) throw new IllegalArgumentException(); boolean wrappedArround = false; if (probability > (1.0 - smallArgumentEnd)) { probability = 1.0 - probability; wrappedArround = true; } if (probability > smallArgumentEnd) { // approximation for intervall 0,138... < probability < 0,861... probability = probability - 0.5; double squaredProbability = probability * probability; double x = probability; x += probability * (squaredProbability * solvePolynomial(squaredProbability, DIVISOR_COEFFICIENTS_0) / solvePolynomial( squaredProbability, DIVIDER_COEFFICIENTS_0)); x = x * rootedPi; return (x); } else { double x = Math.sqrt(-2.0 * Math.log(probability)); double inversedX = 1.0 / x; if (x < 8.0) { // equal to probability > exp(-32) // approximation for intervall exp(-32) < probability < 0,138... // or 0,861 < probability < 1 - exp(-32) x = (x - Math.log(x) / x) - inversedX * solvePolynomial(inversedX, DIVISOR_COEFFICIENTS_1) / solvePolynomial(inversedX, DIVIDER_COEFFICIENTS_1); } else { // approximation for intervall 0 < probability < exp(-32) or 1 - // exp(-32) < probability < 1 x = (x - Math.log(x) / x) - inversedX * solvePolynomial(inversedX, DIVISOR_COEFFICIENTS_3) / solvePolynomial(inversedX, DIVIDER_COEFFICIENTS_3); } if (!wrappedArround) { x = -x; } return (x); } } /** * Solves a given polynomial at x. The polynomial is given by the * coefficients. The coefficients are stored in natural order: * coefficients[i] : c_i*x^i */ public static double solvePolynomial(double x, double[] coefficients) { double value = coefficients[0]; for (int i = 1; i < coefficients.length; i++) { value += coefficients[i] * Math.pow(x, i); } return value; } /** * @param v * a vector values * @param a * a threeshold, only values greater equal this value are used in * the calculation * @return the variance */ public static double variance(double v[], double a) { // calc mean double sum = 0.0; int counter = 0; for (int i = 0; i < v.length; i++) { if (v[i] >= a) { sum = sum + v[i]; counter++; } } double mean = sum / counter; sum = 0.0; counter = 0; for (int i = 0; i < v.length; i++) { if (v[i] >= a) { sum = sum + (v[i] - mean) * (v[i] - mean); counter++; } } double variance = sum / counter; return variance; } public static double correlation(double[] x1, double[] x2) { // Calculate the mean and stddev int counter = 0; double sum1 = 0.0; double sum2 = 0.0; double sumS1 = 0.0; double sumS2 = 0.0; for (int i = 0; i < x1.length; i++) { sum1 = sum1 + x1[i]; sum2 = sum2 + x2[i]; counter++; } double mean1 = sum1 / counter; double mean2 = sum2 / counter; double sum = 0.0; counter = 0; for (int i = 0; i < x1.length; i++) { sum = sum + (x1[i] - mean1) * (x2[i] - mean2); sumS1 = sumS1 + (x1[i] - mean1) * (x1[i] - mean1); sumS2 = sumS2 + (x2[i] - mean2) * (x2[i] - mean2); counter++; } return sum / Math.sqrt(sumS1 * sumS2); } public static double robustMin(double m1, double m2) { double min = Math.min(m1, m2); if (!Double.isNaN(min)) { return min; } else { if (Double.isNaN(m1)) { return m2; } else { return m1; } } } public static double robustMax(double m1, double m2) { double max = Math.max(m1, m2); if (!Double.isNaN(max)) { return max; } else { if (Double.isNaN(m1)) { return m2; } else { return m1; } } } /** * This method returns the logarithmus dualis from value * * @param value the value * @return the log2 of value */ public static double ld(double value) { return Math.log(value) / log2; } }