import java.awt.*;
import java.util.*;
import java.io.*;
import java.lang.*;

/**
 * This class implements and tests DePril's algorithm.
 *
 * In order to execute this program:
 * Save this file as DePril.java 
 * Run: javac DePril.java, this gives you DePril.class
 * Run: java DePril, this executes your program
 */
public class DePril {

public static void main( String[] args ) throws Exception {

        int a = 2;
	int b = 2;
	
	int[][] n_ij = new int[a+1][b+1];  // Here: constant for all classes
	
	// Always start at 1 to be consistent with lecture
   	for (int i = 1; i <= a; i++) {
	   for (int j = 1; j <= b; j++) {
		 n_ij[i][j] = 4; 
           }
	}		
	
	int[] m_i = new int[a+1];
	
	for (int i = 1; i <= a; i++) {
	    m_i[i] = 9;
	
	}
		
	int m = 0;
	   
   	for (int i = 1; i <= a; i++) {
	   int sum = 0;
	   for (int j = 1; j <= b; j++) {
	      sum = sum + n_ij[i][j]*m_i[i];
	   }
	   m = m + sum;
	}
	
	// Let's check m
	System.out.println("m = " + m); // Here: m = 144	
	 
	double[] p     = new double[m+1];
	double[][][] v = new double[m+1][a+1][b+1];
	
	// up to b+1 to be consistent with lecture
	double[] theta = new double[b+1];
	theta[1] = 0.015;
	theta[2] = 0.02;
	
	double prob_sum = 0;  // just to check afterwards
	

   /* Initialization of p_ki */
   		   	
	// Special case: all entries are equal		
	double[][] p_ki = new double[a+1][10];
	for( int l = 1; l <= 9; l++ ) {
	    p_ki[1][l]= (double) 1 / (double) 9;
	} 
	
	p_ki[2][1]= (double) 0.2;
	p_ki[2][2]= (double) 0.15;
	p_ki[2][3]= (double) 0.1;
	p_ki[2][4]= (double) 0.05;
	p_ki[2][5]= (double) 0.15;
	p_ki[2][6]= (double) 0.05;
	p_ki[2][7]= (double) 0.075;
	p_ki[2][8]= (double) 0.05;
	p_ki[2][9]= (double) 0.175;
	

	
   /* computation of p[0] according to Theorem 4.4.1 */
   	
	double p0 = 1;
	
	for (int i = 1; i <= a; i++) {
	   for (int j = 1; j <= b; j++) {
	      double factor = Math.pow((1-theta[j]), n_ij[i][j]);
	      p0 = p0 * factor;
	   }
	}
	
	p[0] = p0;
	prob_sum = prob_sum + p[0];
	
	System.out.println();
	System.out.println("k        p[k]");
	System.out.println();
	System.out.println(0 + " " + p[0]);
	
   /* Initialization of v[0][i][j] according to Theorem 4.4.1 */
   	
	for (int i = 1; i <= a; i++) {
	   for (int j = 1; j <= b; j++) {
	      v[0][i][j] = 0;
	   }
	}
	

   /* Computation of p[k], k=1,...,m, (according to Theorem 4.4.1) */
   		
	for (int k = 1; k <= m; k++) {  
	   double sum = 0;
	   double summand = 0;
	   
	   for (int i = 1; i <= a; i++) {
	      for (int j = 1; j <= b; j++) {
	         sum = 0;
		 for (int l = 1; l <= Math.min(k,m_i[i]); l++) { 
		    summand = p_ki[i][l] * (l * p[k-l] - v[k-l][i][j]); 
		    sum = sum + summand; 
		 }
		 
		 v[k][i][j] = ((double) theta[j] / (1-theta[j])) * sum; 
	      }
	   }
	   
	   sum = 0;
	   
   	   for (int i = 1; i <= a; i++) {
	      for (int j = 1; j <= b; j++) {
		 summand = n_ij[i][j] * v[k][i][j];
		 sum = sum + summand;
	      }
	   }
	   
	   p[k] = ((double) 1 / k) * sum;
	   prob_sum = prob_sum + p[k];
	   System.out.println(k + " " + p[k]);
	}	

	System.out.println();
	
	// just to be sure ...
	System.out.println("Total sum of probabilities: " + prob_sum);
  }
}
