// File: jc-kim[P]swaptions/HJM_Swaption_Blocking.cpp
// Function: HJM_Swaption_Blocking(double*, double, double, double, double, double, int, int, double, double*, double*, long, long, int, int, double*, double*, double*, double*, double*, double*, double*, double*, double*, double*, double*, double*)
int HJM_Swaption_Blocking(FTYPE *pdSwaptionPrice, //Output vector that will store simulation results in the form:
    //Swaption Price
    //Swaption Standard Error
    //Swaption Parameters
    FTYPE dStrike,
    FTYPE dCompounding,     //Compounding convention used for quoting the strike (0 => continuous,
    //0.5 => semi-annual, 1 => annual).
    FTYPE dMaturity,	      //Maturity of the swaption (time to expiration)
    FTYPE dTenor,	      //Tenor of the swap
    FTYPE dPaymentInterval, //frequency of swap payments e.g. dPaymentInterval = 0.5 implies a swap payment every half
    //year
    //HJM Framework Parameters (please refer HJM.cpp for explanation of variables and functions)
    int iN,
    int iFactors,
    FTYPE dYears,
    FTYPE *pdYield,
    FTYPE *ppdFactors,
    //Simulation Parameters
    long iRndSeed,
    long lTrials,
    int BLOCKSIZE, int tid,
		FTYPE *ppdHJMPath, FTYPE *pdForward, FTYPE *ppdDrifts, FTYPE *pdTotalDrift,
		FTYPE *pdDiscountingRatePath, FTYPE *pdPayoffDiscountFactors, FTYPE *pdSwapRatePath, FTYPE *pdSwapDiscountFactors, FTYPE *pdSwapPayoffs,
		FTYPE *pdZ, FTYPE *randZ,
		FTYPE *pdexpRes)
{
  int iSuccess = 0;
  int i;
  int b; //block looping variable
  long l; //looping variables

  FTYPE ddelt = (FTYPE)(dYears/iN);
  int iFreqRatio = (int)(dPaymentInterval/ddelt + 0.5);
  FTYPE dStrikeCont;
	dStrikeCont = dCompounding == 0 ? dStrike: (1 / dCompounding) * log(1 + dStrike * dCompounding);  

	int iSwapVectorLength = (int)(iN - dMaturity / ddelt + 0.5);

  int iSwapStartTimeIndex;
  int iSwapTimePoints;
  FTYPE dSwapVectorYears;

  FTYPE dSwaptionPayoff;
  FTYPE dDiscSwaptionPayoff;
  FTYPE dFixedLegValue;

  // Accumulators
  FTYPE dSumSimSwaptionPrice; 
  FTYPE dSumSquareSimSwaptionPrice;

  // Final returned results
  FTYPE dSimSwaptionMeanPrice;
  FTYPE dSimSwaptionStdError;

  iSwapStartTimeIndex = (int)(dMaturity/ddelt + 0.5);	//Swap starts at swaption maturity
  iSwapTimePoints = (int)(dTenor/ddelt + 0.5);			//Total HJM time points corresponding to the swap's tenor
  dSwapVectorYears = (FTYPE)(iSwapVectorLength*ddelt);

  for (i = 0; i < iSwapVectorLength; i++) pdSwapPayoffs[i] = 0.0;
  for (i = iFreqRatio; i <= iSwapTimePoints; i += iFreqRatio) {
    if(i != iSwapTimePoints)
      pdSwapPayoffs[i] = exp(dStrikeCont * dPaymentInterval) - 1;
    else
      pdSwapPayoffs[i] = exp(dStrikeCont * dPaymentInterval);
  }

  //generating forward curve at t=0 from supplied yield curve
  iSuccess = HJM_Yield_to_Forward(pdForward, iN, pdYield);
  if(iSuccess != 1) return iSuccess;

  //computation of drifts from factor volatilities
  iSuccess = HJM_Drifts(pdTotalDrift, ppdDrifts, iN, iFactors, dYears, ppdFactors);
  if(iSuccess != 1) return iSuccess;

  dSumSimSwaptionPrice = 0.0;
  dSumSquareSimSwaptionPrice = 0.0;

  //Simulations begin:
  for(l = 0; l < lTrials; l += BLOCKSIZE) {
    //For each trial a new HJM Path is generated
    /* GC: 51% of the time goes here */
    iSuccess = HJM_SimPath_Forward_Blocking(ppdHJMPath, iN, iFactors, dYears, pdForward, pdTotalDrift, ppdFactors, &iRndSeed, BLOCKSIZE, pdZ, randZ);
    if(iSuccess != 1) return iSuccess;

    //now we compute the discount factor vector
    for(i = 0; i < iN; i++){
      for(b = 0; b < BLOCKSIZE; b++){
        pdDiscountingRatePath[BLOCKSIZE*i + b] = ppdHJMPath[i * iN * BLOCKSIZE + b];
      }
    }

    /* 15% of the time goes here */
    iSuccess = Discount_Factors_Blocking(pdPayoffDiscountFactors, iN, dYears, pdDiscountingRatePath, BLOCKSIZE, pdexpRes);
    if(iSuccess != 1) return iSuccess;

    //now we compute discount factors along the swap path
    for(i = 0; i < iSwapVectorLength; i++){
      for(b = 0; b < BLOCKSIZE; b++){
        pdSwapRatePath[i * BLOCKSIZE + b] = ppdHJMPath[iSwapStartTimeIndex * iN * BLOCKSIZE + i * BLOCKSIZE + b];
      }
    }

    iSuccess = Discount_Factors_Blocking(pdSwapDiscountFactors, iSwapVectorLength, dSwapVectorYears, pdSwapRatePath, BLOCKSIZE, pdexpRes);
    if(iSuccess != 1) return iSuccess;

    // Simulation
    for(b = 0; b < BLOCKSIZE; b++){
      dFixedLegValue = 0.0;

      for(i = 0; i < iSwapVectorLength; i++) dFixedLegValue += pdSwapPayoffs[i] * pdSwapDiscountFactors[i*BLOCKSIZE + b];
      dSwaptionPayoff = dMax(dFixedLegValue - 1.0, 0);

      dDiscSwaptionPayoff = dSwaptionPayoff * pdPayoffDiscountFactors[iSwapStartTimeIndex*BLOCKSIZE + b];
      // end simulation

      // accumulate into the aggregating variables
      dSumSimSwaptionPrice += dDiscSwaptionPayoff;
      dSumSquareSimSwaptionPrice += dDiscSwaptionPayoff*dDiscSwaptionPayoff;
    }
  }

  // Simulation Results Stored
  dSimSwaptionMeanPrice = dSumSimSwaptionPrice / lTrials;
  dSimSwaptionStdError = sqrt((dSumSquareSimSwaptionPrice-dSumSimSwaptionPrice*dSumSimSwaptionPrice/lTrials)/
      (lTrials-1.0))/sqrt((FTYPE)lTrials);

  //results returned
  pdSwaptionPrice[0] = dSimSwaptionMeanPrice;
  pdSwaptionPrice[1] = dSimSwaptionStdError;

  return 1;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %rbx
subq $0x118, %rsp            # imm = 0x118
movq 0x80(%rbp), %rax
movq 0x78(%rbp), %rax
movq 0x70(%rbp), %rax
movq 0x68(%rbp), %rax
movq 0x60(%rbp), %rax
movq 0x58(%rbp), %rax
movq 0x50(%rbp), %rax
movq 0x48(%rbp), %rax
movq 0x40(%rbp), %rax
movq 0x38(%rbp), %rax
movq 0x30(%rbp), %rax
movq 0x28(%rbp), %rax
movl 0x20(%rbp), %eax
movl 0x18(%rbp), %eax
movq 0x10(%rbp), %rax
movq %rdi, -0x18(%rbp)
movsd %xmm0, -0x20(%rbp)
movsd %xmm1, -0x28(%rbp)
movsd %xmm2, -0x30(%rbp)
movsd %xmm3, -0x38(%rbp)
movsd %xmm4, -0x40(%rbp)
movl %esi, -0x44(%rbp)
movl %edx, -0x48(%rbp)
movsd %xmm5, -0x50(%rbp)
movq %rcx, -0x58(%rbp)
movq %r8, -0x60(%rbp)
movq %r9, -0x68(%rbp)
movl $0x0, -0x6c(%rbp)
movsd -0x50(%rbp), %xmm0
cvtsi2sdl -0x44(%rbp), %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, -0x88(%rbp)
movsd -0x40(%rbp), %xmm0
divsd -0x88(%rbp), %xmm0
movsd 0x1a51(%rip), %xmm1     # 0x5010
addsd %xmm1, %xmm0
cvttsd2si %xmm0, %eax
movl %eax, -0x8c(%rbp)
movsd -0x28(%rbp), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0x35ec
jp 0x35ec
movsd -0x20(%rbp), %xmm0
movsd %xmm0, -0xf0(%rbp)
jmp 0x3637
movsd 0x1a24(%rip), %xmm0     # 0x5018
divsd -0x28(%rbp), %xmm0
movsd %xmm0, -0xf8(%rbp)
movsd -0x20(%rbp), %xmm0
movsd -0x28(%rbp), %xmm1
mulsd %xmm1, %xmm0
movsd 0x1a01(%rip), %xmm1     # 0x5018
addsd %xmm1, %xmm0
callq 0x2100
movaps %xmm0, %xmm1
movsd -0xf8(%rbp), %xmm0
mulsd %xmm1, %xmm0
movsd %xmm0, -0xf0(%rbp)
movsd -0xf0(%rbp), %xmm0
movsd %xmm0, -0x98(%rbp)
cvtsi2sdl -0x44(%rbp), %xmm0
movsd -0x30(%rbp), %xmm1
divsd -0x88(%rbp), %xmm1
subsd %xmm1, %xmm0
movsd 0x19ab(%rip), %xmm1     # 0x5010
addsd %xmm1, %xmm0
cvttsd2si %xmm0, %eax
movl %eax, -0x9c(%rbp)
movsd -0x30(%rbp), %xmm0
divsd -0x88(%rbp), %xmm0
movsd 0x1988(%rip), %xmm1     # 0x5010
addsd %xmm1, %xmm0
cvttsd2si %xmm0, %eax
movl %eax, -0xa0(%rbp)
movsd -0x38(%rbp), %xmm0
divsd -0x88(%rbp), %xmm0
movsd 0x1965(%rip), %xmm1     # 0x5010
addsd %xmm1, %xmm0
cvttsd2si %xmm0, %eax
movl %eax, -0xa4(%rbp)
cvtsi2sdl -0x9c(%rbp), %xmm0
mulsd -0x88(%rbp), %xmm0
movsd %xmm0, -0xb0(%rbp)
movl $0x0, -0x70(%rbp)
movl -0x70(%rbp), %eax
cmpl -0x9c(%rbp), %eax
jge 0x36fe
movq 0x68(%rbp), %rax
movslq -0x70(%rbp), %rcx
xorps %xmm0, %xmm0
movsd %xmm0, (%rax,%rcx,8)
movl -0x70(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x70(%rbp)
jmp 0x36d8
movl -0x8c(%rbp), %eax
movl %eax, -0x70(%rbp)
movl -0x70(%rbp), %eax
cmpl -0xa4(%rbp), %eax
jg 0x3779
movl -0x70(%rbp), %eax
cmpl -0xa4(%rbp), %eax
je 0x374a
movsd -0x98(%rbp), %xmm0
mulsd -0x40(%rbp), %xmm0
callq 0x2250
movsd 0x18e1(%rip), %xmm1     # 0x5018
subsd %xmm1, %xmm0
movq 0x68(%rbp), %rax
movslq -0x70(%rbp), %rcx
movsd %xmm0, (%rax,%rcx,8)
jmp 0x3769
movsd -0x98(%rbp), %xmm0
mulsd -0x40(%rbp), %xmm0
callq 0x2250
movq 0x68(%rbp), %rax
movslq -0x70(%rbp), %rcx
movsd %xmm0, (%rax,%rcx,8)
jmp 0x376b
movl -0x8c(%rbp), %eax
addl -0x70(%rbp), %eax
movl %eax, -0x70(%rbp)
jmp 0x3707
movq 0x30(%rbp), %rdi
movl -0x44(%rbp), %esi
movq -0x58(%rbp), %rdx
callq 0x3070
movl %eax, -0x6c(%rbp)
cmpl $0x1, -0x6c(%rbp)
je 0x379d
movl -0x6c(%rbp), %eax
movl %eax, -0xc(%rbp)
jmp 0x3b68
movq 0x40(%rbp), %rdi
movq 0x38(%rbp), %rsi
movl -0x44(%rbp), %edx
movl -0x48(%rbp), %ecx
movsd -0x50(%rbp), %xmm0
movq -0x60(%rbp), %r8
callq 0x3110
movl %eax, -0x6c(%rbp)
cmpl $0x1, -0x6c(%rbp)
je 0x37cd
movl -0x6c(%rbp), %eax
movl %eax, -0xc(%rbp)
jmp 0x3b68
xorps %xmm0, %xmm0
movsd %xmm0, -0xd0(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0xd8(%rbp)
movq $0x0, -0x80(%rbp)
movq -0x80(%rbp), %rax
cmpq 0x10(%rbp), %rax
jge 0x3abb
movq 0x28(%rbp), %rdi
movl -0x44(%rbp), %esi
movl -0x48(%rbp), %edx
movsd -0x50(%rbp), %xmm0
movq 0x30(%rbp), %rcx
movq 0x40(%rbp), %r8
movq -0x60(%rbp), %r9
movl 0x18(%rbp), %r11d
movq 0x70(%rbp), %r10
movq 0x78(%rbp), %rax
leaq -0x68(%rbp), %rbx
movq %rbx, (%rsp)
movl %r11d, 0x8(%rsp)
movq %r10, 0x10(%rsp)
movq %rax, 0x18(%rsp)
callq 0x2d70
movl %eax, -0x6c(%rbp)
cmpl $0x1, -0x6c(%rbp)
je 0x3850
movl -0x6c(%rbp), %eax
movl %eax, -0xc(%rbp)
jmp 0x3b68
movl $0x0, -0x70(%rbp)
movl -0x70(%rbp), %eax
cmpl -0x44(%rbp), %eax
jge 0x38b6
movl $0x0, -0x74(%rbp)
movl -0x74(%rbp), %eax
cmpl 0x18(%rbp), %eax
jge 0x38a9
movq 0x28(%rbp), %rax
movl -0x70(%rbp), %ecx
imull -0x44(%rbp), %ecx
imull 0x18(%rbp), %ecx
addl -0x74(%rbp), %ecx
movslq %ecx, %rcx
movsd (%rax,%rcx,8), %xmm0
movq 0x48(%rbp), %rax
movl 0x18(%rbp), %ecx
imull -0x70(%rbp), %ecx
addl -0x74(%rbp), %ecx
movslq %ecx, %rcx
movsd %xmm0, (%rax,%rcx,8)
movl -0x74(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x74(%rbp)
jmp 0x3866
jmp 0x38ab
movl -0x70(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x70(%rbp)
jmp 0x3857
movq 0x50(%rbp), %rdi
movl -0x44(%rbp), %esi
movsd -0x50(%rbp), %xmm0
movq 0x48(%rbp), %rdx
movl 0x18(%rbp), %ecx
movq 0x80(%rbp), %r8
callq 0x3380
movl %eax, -0x6c(%rbp)
cmpl $0x1, -0x6c(%rbp)
je 0x38e9
movl -0x6c(%rbp), %eax
movl %eax, -0xc(%rbp)
jmp 0x3b68
movl $0x0, -0x70(%rbp)
movl -0x70(%rbp), %eax
cmpl -0x9c(%rbp), %eax
jge 0x395e
movl $0x0, -0x74(%rbp)
movl -0x74(%rbp), %eax
cmpl 0x18(%rbp), %eax
jge 0x3951
movq 0x28(%rbp), %rax
movl -0xa0(%rbp), %ecx
imull -0x44(%rbp), %ecx
imull 0x18(%rbp), %ecx
movl -0x70(%rbp), %edx
imull 0x18(%rbp), %edx
addl %edx, %ecx
addl -0x74(%rbp), %ecx
movslq %ecx, %rcx
movsd (%rax,%rcx,8), %xmm0
movq 0x58(%rbp), %rax
movl -0x70(%rbp), %ecx
imull 0x18(%rbp), %ecx
addl -0x74(%rbp), %ecx
movslq %ecx, %rcx
movsd %xmm0, (%rax,%rcx,8)
movl -0x74(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x74(%rbp)
jmp 0x3902
jmp 0x3953
movl -0x70(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x70(%rbp)
jmp 0x38f0
movq 0x60(%rbp), %rdi
movl -0x9c(%rbp), %esi
movsd -0xb0(%rbp), %xmm0
movq 0x58(%rbp), %rdx
movl 0x18(%rbp), %ecx
movq 0x80(%rbp), %r8
callq 0x3380
movl %eax, -0x6c(%rbp)
cmpl $0x1, -0x6c(%rbp)
je 0x3997
movl -0x6c(%rbp), %eax
movl %eax, -0xc(%rbp)
jmp 0x3b68
movl $0x0, -0x74(%rbp)
movl -0x74(%rbp), %eax
cmpl 0x18(%rbp), %eax
jge 0x3aa8
xorps %xmm0, %xmm0
movsd %xmm0, -0xc8(%rbp)
movl $0x0, -0x70(%rbp)
movl -0x70(%rbp), %eax
cmpl -0x9c(%rbp), %eax
jge 0x3a0d
movq 0x68(%rbp), %rax
movslq -0x70(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm0
movq 0x60(%rbp), %rax
movl -0x70(%rbp), %ecx
imull 0x18(%rbp), %ecx
addl -0x74(%rbp), %ecx
movslq %ecx, %rcx
movsd (%rax,%rcx,8), %xmm2
movsd -0xc8(%rbp), %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, -0xc8(%rbp)
movl -0x70(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x70(%rbp)
jmp 0x39bc
movsd -0xc8(%rbp), %xmm0
movsd 0x15fb(%rip), %xmm1     # 0x5018
subsd %xmm1, %xmm0
xorps %xmm1, %xmm1
callq 0x2640
movsd %xmm0, -0xb8(%rbp)
movsd -0xb8(%rbp), %xmm0
movq 0x50(%rbp), %rax
movl -0xa0(%rbp), %ecx
imull 0x18(%rbp), %ecx
addl -0x74(%rbp), %ecx
movslq %ecx, %rcx
mulsd (%rax,%rcx,8), %xmm0
movsd %xmm0, -0xc0(%rbp)
movsd -0xc0(%rbp), %xmm0
addsd -0xd0(%rbp), %xmm0
movsd %xmm0, -0xd0(%rbp)
movsd -0xc0(%rbp), %xmm0
movsd -0xc0(%rbp), %xmm2
movsd -0xd8(%rbp), %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, -0xd8(%rbp)
movl -0x74(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x74(%rbp)
jmp 0x399e
jmp 0x3aaa
movslq 0x18(%rbp), %rax
addq -0x80(%rbp), %rax
movq %rax, -0x80(%rbp)
jmp 0x37eb
movsd -0xd0(%rbp), %xmm0
cvtsi2sdq 0x10(%rbp), %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, -0xe0(%rbp)
movsd -0xd8(%rbp), %xmm0
movsd -0xd0(%rbp), %xmm1
mulsd -0xd0(%rbp), %xmm1
cvtsi2sdq 0x10(%rbp), %xmm2
divsd %xmm2, %xmm1
subsd %xmm1, %xmm0
cvtsi2sdq 0x10(%rbp), %xmm1
movsd 0x150f(%rip), %xmm2     # 0x5018
subsd %xmm2, %xmm1
divsd %xmm1, %xmm0
callq 0x20e0
movsd %xmm0, -0x100(%rbp)
cvtsi2sdq 0x10(%rbp), %xmm0
callq 0x20e0
movaps %xmm0, %xmm1
movsd -0x100(%rbp), %xmm0
divsd %xmm1, %xmm0
movsd %xmm0, -0xe8(%rbp)
movsd -0xe0(%rbp), %xmm0
movq -0x18(%rbp), %rax
movsd %xmm0, (%rax)
movsd -0xe8(%rbp), %xmm0
movq -0x18(%rbp), %rax
movsd %xmm0, 0x8(%rax)
movl $0x1, -0xc(%rbp)
movl -0xc(%rbp), %eax
addq $0x118, %rsp            # imm = 0x118
popq %rbx
popq %rbp
retq
nopw %cs:(%rax,%rax)
nop