import java.util.*;
import java.io.*;
import java.lang.*;

/**
 * Diese Klasse implementiert den Panjer-Algorithmus im
 * Falle diskreter Schadenhöhen.
 *
 * @author    Hendrik Schmidt 
 * @version   1.0, 23-01-03
 */
public class Panjer {

    // Globale Variable
    /** Paramter der Verteilung von N. */
    static double p = 100.0/101.0;
    /** Paramter der Verteilung von U.*/
    static double delta = 1.0;
    /** Schrittweite. */
    static double h = 0.01;
    /** Anzahl der Schritte. */
    static int n = 201;
    /** Paramter a der Panjer-Rekursion. */
    static double a = p;
    /** Paramter b der Panjer-Rekursion. */
    static double b = 0.0;

    /** 
     * Main method für die Berechnung der Wahrscheinlichkeiten
     * nach Panjer.
     */
    public static void main (String[] args) {

	// Berechnung der Schadenhöhen-Verteilung
	double[] q = new double[n];
	
	for (int i = 0; i < n; i++) {
	    q[i] = getExpCDF(delta,h*(((double) i) + 1.0)) - 
                   getExpCDF(delta,h*((double) i));
	}

	// Berechnung der Panjer-Wahrscheinlichkeiten	  
	double[] pX = new double[n];
	
	pX = getPanjer(n,((1.0-p)/(1.0-a*q[0])),q,a,b);

	// Berechnung der Tailwahrscheinlichkeiten	
	double[] rx = new double[n];
	rx[0] = 1 - pX[0];

	for (int i = 1; i < n; i++) {
	    rx[i] = rx[i-1] - pX[i];
	} 
	
	// Ausgabe der Tailwahrscheinlichkeiten
	System.out.println("h*i     TailProb(h*i)");
	for (int i = 20; i < n; i+=20) {
	    System.out.println(((double) i)*h + "     " + rx[i]);
	}
	
	// Alternative für die Ausgabe
	System.out.println();
	System.out.println("h*i     TailProb(h*i)");
	for (int i = 20; i < n; i+=20) {
	    double wktsum = 0.0;
	    for (int j = 0; j <= i; j++) {
		wktsum += pX[j];
	    }
	    double tailprob = 1.0 - wktsum;
	    System.out.println(((double) i)*h + "     "  + tailprob);
	}
	
    }

    /**
     * Diese Methode liefert die Werte von px, d.h.
     * die Wkt., dass X=j für j von 0 bis n
     *
     * @param n      die Anzahl der Iterationen.
     * @param p0     die Wkt., dass X = 0.
     * @param q      die Wkt.-werte von U.
     * @param a      die Variable a in der Panjer Rekursionsformel.
     * @param b      die Variable b in der Panjer Rekursionsformel.
     * @return       die Werte von px.
     */
    public static double[] getPanjer (int n, double p0, 
                                 double[] q, double a, double b) {

	double[] px = new double[n];
	px[0] = p0;
	double u = 1.0/(1.0-a*q[0]);

	for (int i = 1; i < n; i++) {
	    double sum = 0.0;
	    for (int j = 1; j <= i; j++) {
		sum += (a + b*((double) j)/((double) i))*q[j]*px[i-j];
	    }
	    px[i] = u * sum;
	}

	return px;
    }

    /**
     * Diese Methode liefert den Wert der Verteilungsfunktion
     * einer Exponentialverteilung.
     *
     * @param lambda   der Paramter der Exponential-Verteilung.
     * @param x        die Stelle, an der die VF ausgewertet wird.
     * @return         der Wert der VF. 
     */ 
    public static double getExpCDF (double lambda, double x) {
	return 1.0 - Math.exp(-lambda*x);
    }


}


