package tr.gov.ulakbim.jDenetX.clusterers.clustream;
import tr.gov.ulakbim.jDenetX.clusterers.clustream.cern.Gamma;
/**
* Helpful static functions.
*
* @author Fernando Sanchez Villaamil
*/
public class AuxiliaryFunctions {
/**
* Number of iterations used to calculate the incomplete gamma function,
* see <code>AuxiliaryFunctions</code>.
* XXX: A good precision value is said to be 100 iterations, but this
* results in double overflows.
*/
public static final int GAMMA_ITERATIONS = 100;
/**
* Private constructor to hinder instantiation.
*/
private AuxiliaryFunctions() {
}
/**
* Calculate the incomplete gamma function on x, a numerically.
*
* @param x
* @param a
* @return gamma(x, a)
*/
private static double incompleteGamma(double a, double x) {
assert (!Double.isNaN(a));
assert (!Double.isNaN(x));
double sum = 0.0;
double xPow = 1; // Start with x^0
for (int n = 0; n < GAMMA_ITERATIONS; n++) {
double denom = a;
for (int i = 1; i <= n; i++) {
denom *= (a + i);
}
assert (denom != 0.0);
sum += xPow / denom;
xPow *= x;
}
double res = Math.pow(x, a) * Math.exp(-x) * sum;
if (Double.isNaN(res)) {
System.err.println("a " + a);
System.err.println("x " + x);
System.err.println("x^a " + Math.pow(x, a));
System.err.println("e^-x " + Math.exp(-x));
System.err.println("sum " + sum);
assert (false);
}
return res;
}
/**
* Calculates gamma(n/2) (special case!) for small n.
*
* @param n
* @return gamma(n/2)
*/
public static double gammaHalf(int n) {
int[] doubleFac = new int[]{1, 1, 2, 3, 8, 15, 48, 105, 384, 945, 3840,
10395, 46080, 135135, 645120, 2027025,
10321920, 34459425, 185794560, 654729075};
if (n == 0) {
return Double.POSITIVE_INFINITY;
}
// Integers are simple fac(n)
if ((n % 2) == 0) {
int v = (n / 2) - 1;
int res = 1;
for (int i = 1; i <= v; i++) {
res *= i;
}
return res;
}
// First two would yeald negative double factorials
if (n == 1) {
return 1.0692226492664116 / 0.6032442812094465;
}
if (n == 3) {
return 0.947573901083827 / 1.0692226492664116;
}
return Math.sqrt(Math.PI) * (doubleFac[n - 2]) / (Math.pow(2, (n - 1) * .5));
}
/**
* Calcuates the probabilty that a point sampled from a gaussian kernel
* has a Malahanobis-distance greater than the given threshold.
*
* @param threshold a threshold for the distance
* @param dimension the number of dimensions of the kernel
* @return the above probability
*/
public static double distanceProbabilty(double threshold, int dimension) {
// threshold = (threshold*threshold) * .5;
if (threshold == 0) {
return 1;
}
//return 1 - (incompleteGamma(dimension * .5, threshold) / gammaHalf(dimension));
return 1 - (Gamma.incompleteGamma(dimension * .5, threshold * .5)
/ gammaHalf(dimension));
}
public static double gompertzWeight(double average, double count) {
if (average < 2.0)
return 1.0;
double logT = Math.log(0.97);
double logt = Math.log(0.0001);
double denomB = (Math.pow(logT * logT, 1 / (average - 2.0)));
double b = (Math.pow(logt * logt, 1.0 / (2.0 * (1.0 - (2.0 / average))))) / denomB;
double c = -(1.0 / average) * Math.log(-(1.0 / b) * logT);
assert (b >= 0) : "Bad b " + b + ", average " + average;
assert (c >= 0) : "Bad c " + c + ", average " + average;
// Should be okay, the following test fails for some numerica
// bad examples
// assert (Math.exp(-b * Math.exp(-c * average)) > 0.95);
// assert (Math.exp(-b * Math.exp(-c * 2)) < 0.001);
return Math.exp(-b * Math.exp(-c * count));
}
}