//package newrussianopt;

/**
 * <p>Title: </p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2002</p>
 * <p>Company: </p>
 * @author unascribed
 * @version 1.0
 */

public class NewRussianOpt {

  double [][] e ;
  int [] h ;
  int n_o ; // h[n] dfnd for n >= n_o
  double p, q, u, alpha, beta, r ;

  final static boolean CHECK_DFND = true ;
  boolean [][] e_dfnd ;

  final static boolean VERBOSE = true ;

  boolean checkAndInitParams(double r, double u, double beta) {

      if (r <= 0.0) {
         if ( VERBOSE ) System.out.println(
         "parameter error: r<=0") ;
         return false ;
      }
      if (u <= ( 1.0 + r ))  {
         if ( VERBOSE ) System.out.println(
         "parameter error: u<=1+r") ;
         return false ;
      }
      if (beta >= 1.0) {
         if ( VERBOSE ) System.out.println(
         "parameter error: beta>=1") ;
         return false ;
      }
      double beta_lb =(1.0+u)*(1.0+r)/(u*(2.0+r)) ;
      if (beta <= beta_lb) {
         if ( VERBOSE ) System.out.println(
         "parameter error: beta<=(1+u)(1+r)/(u(2+r))") ;
         return false ;
      }

      alpha = 1.0 / (1.0+r) ;
      p = ( u * (1.0+r) - 1.0 )/ ( u*u-1.0 ) ;
      q = 1.0 - p ;

      this.r = r ;
      this.u = u ;
      this.beta = beta ;
if ( VERBOSE ) {
   System.out.println("alpha="+alpha) ;
   System.out.println("beta="+beta) ;
   System.out.println("r="+r) ;
   System.out.println("u="+u) ;
   System.out.println("p="+p) ;
   System.out.println("q="+q) ;
}
      return true ;

  }

  void initArrays(int nn) {
      e = new double[nn+1][nn+1] ;
      h = new int[nn+1] ;
if ( VERBOSE ) System.out.println("nn="+nn) ;
      if ( CHECK_DFND ) {
         e_dfnd = new boolean[nn+1][nn+1] ;
         for ( int i=0; i<nn+1; i++ ) {
            for ( int j=0; j<nn+1; j++ )
               e_dfnd[i][j] = false ;
         }
      }
  }

  double optLiability( int n, int j, int k ) {
      return Math.pow(beta,n) * Math.pow(u,k) ;
  }

  int piOpr( int i, int j ) {
      if ( (i%2)==(j%2) ) return 0 ;
      return 1 ;
  }

  double getValue( int n, int j, int k ) {
      int delta = k-j ;
      // ASSERT  delta>=0
      if ((n>=n_o)&&(delta>=h[n]))
         return optLiability(n,j,k) ;
      int l = k - piOpr(n, delta ) ;
      if( CHECK_DFND && !e_dfnd[n][delta] ) {
         System.out.println("e["+n+","+delta+
         "] required and not defined.") ;
      }
      return Math.pow(u,l) * e[n][delta] ;
  }

  double eFormula( int n, int j, int k ) {
     int l = ((j+1)>k)? (j+1) : k ;
     return alpha * ( p*getValue(n+1,j+1,l)
                 + q*getValue(n+1,j-1,k) ) ;

  }

  void initValues(int nn) {
      h[nn] = 0 ;
      n_o = nn ;
      for ( int n=nn-1; n>=0; n-- ) {
         for ( int delta=0; delta<=n; delta++ ) {
             int k = piOpr(n,delta) ;
             int j = k - delta ;
             double ee = eFormula( n,j,k ) ;
             if ( ee < optLiability(n,j,k) ) {
                h[n] = delta ;
                n_o = n ;
                break ;
             }
             e[n][delta] = ee ;
             if ( CHECK_DFND ) e_dfnd[n][delta] = true ;
         }
      }
  }

  void printEntry( int n, int delta, int j, int k, double ee ) {
     System.out.println("("+n+","+j+","+k+") [delta="+delta+"] "+ee ) ;
  }

  void printValues() {
     System.out.println("\nn_o="+n_o) ;
     int nn = h.length -1 ;
     for ( int n=0; n<=nn; n++ ) {
        for ( int delta=0; delta<=n; delta ++ ) {
          int k = piOpr(n,delta) ;
          int j = k - delta ;
          if ((n >=n_o) && (delta > h[n])) break ;
          printEntry(n,delta,j,k,getValue(n,j,k) ) ;
        }
     }
  }

  boolean initAll( int nn, double r, double u, double beta ) {
     if ( !checkAndInitParams(r,u,beta) ) {
        System.out.println("Error: failed check parameters.") ;
        return false ;
     }
     initArrays(nn) ;
     initValues(nn) ;
     return true ;
  }

  void printExerciseBoundary() {
     int nn = h.length -1 ;
     System.out.println("\nExercise Boundary") ;
     System.out.println("n_o="+n_o+"\n") ;
     for ( int n=0; n<=nn; n++ ) {
        System.out.println("h["+n+"]="+((n<n_o)?n_o:h[n])) ;
     }
  }

  public static void main(String[] args) {
     NewRussianOpt nro = new NewRussianOpt() ;
     nro.initAll( 40, 0.01, 1.2, .99) ;
     nro.printValues() ;
     nro.printExerciseBoundary() ;
  }
}
