package com.spbsu.bernulli.caches;
import org.apache.commons.math3.special.Gamma;
import java.util.Arrays;
public class Digamma1Cache {
int maxOffset;
double base;
final double[] values;
final boolean[] cached;
public Digamma1Cache(double base, int n) {
values = new double[n + 2];
cached = new boolean[n + 2];
this.base = base;
this.maxOffset = n;
}
// limits for switching algorithm in digamma
/**
* C limit.
*/
private static final double C_LIMIT = 49;
/**
* S limit.
*/
private static final double S_LIMIT = 1e-5;
public final double calculate(int offset) {
if (cached[offset]) {
return values[offset];
} else {
double x = base + offset;
if (x > 0 && x <= S_LIMIT) {
// use method 5 from Bernardo AS103
// accurate to O(x)
values[offset] = 1.0 / (x * x);
cached[offset] = true;
} else if (x >= C_LIMIT) {
final double inv = 1.0 / (x * x);
// 1 1 1 1 1
// - + ---- + ---- - ----- + -----
// x 2 3 5 7
// 2 x 6 x 30 x 42 x
values[offset] = 1.0 / x + inv / 2 + inv / x * (1.0 / 6 - inv * (1.0 / 30 + inv / 42));
cached[offset] = true;
} else if (offset == (maxOffset + 1)) {
cached[offset] = true;
values[offset] = Gamma.trigamma(base + offset);
} else {
values[offset] = calculate(offset + 1) + 1 / (x * x);
cached[offset] = true;
}
}
return values[offset];
}
final public void update(double newBase) {
if (this.base == newBase)
return;
this.base = newBase;
Arrays.fill(cached, false);
}
}