/* * Copyright (c) 2010 Ghais Issa and others. All rights reserved. * Licensed 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. */ package org.streaminer.stream.sampler.gamma; import java.util.Random; /** * Implementation of the Z algorithm. * @author Ghais Issa */ final public class Z implements GammaFunction { private static Random generator = new Random(); private final int n; private double w; public Z(int n) { super(); this.n = n; this.w = Math.exp(-Math.log(generator.nextDouble()) / n); } @Override public long apply(long t) { double term = t - this.n + 1; double u; double x; long gamma; while (true) { //generate u and x u = generator.nextDouble(); x = t * (this.w - 1.0); gamma = (long) x; //test if u <= h(gamma)/cg(x) double lhs = Math.exp(Math.log(((u * Math.pow(((t + 1) / term), 2)) * (term + gamma)) / (t + x)) / this.n); double rhs = (((t + x) / (term + gamma)) * term) / t; if (lhs < rhs) { this.w = rhs / lhs; break; } //test if u <= f(gamma)/cg(x) double y = (((u * (t + 1)) / term) * (t + gamma + 1)) / (t + x); double denom; double number_lim; if (this.n < gamma) { denom = t; number_lim = term + gamma; } else { denom = t - this.n + gamma; number_lim = t + 1; } for (long number = t + gamma; number >= number_lim; number--) { y = (y * number) / denom; denom = denom - 1; } this.w = Math.exp(-Math.log(generator.nextDouble()) / this.n); if (Math.exp(Math.log(y) / this.n) <= (t + x) / t) { break; } } return gamma; } }