@Test
 public void greekTest() {
   final LatticeSpecification[] lattices =
       new LatticeSpecification[] {
         new CoxRossRubinsteinLatticeSpecification(),
         new JarrowRuddLatticeSpecification(),
         new TrigeorgisLatticeSpecification(),
         new JabbourKraminYoungLatticeSpecification(),
         new TianLatticeSpecification()
       };
   final boolean[] tfSet = new boolean[] {true, false};
   for (final LatticeSpecification lattice : lattices) {
     for (final boolean isCall : tfSet) {
       for (final double strike : STRIKES) {
         for (final double interest : INTERESTS) {
           for (final double vol : VOLS) {
             final int[] choicesSteps = new int[] {31, 112, 301};
             for (final int nSteps : choicesSteps) {
               for (final double dividend : DIVIDENDS) {
                 final OptionFunctionProvider1D function =
                     new EuropeanVanillaOptionFunctionProvider(strike, TIME, nSteps, isCall);
                 final GreekResultCollection resDiv =
                     _model.getGreeks(lattice, function, SPOT, vol, interest, dividend);
                 final double priceDiv =
                     BlackScholesFormulaRepository.price(
                         SPOT, strike, TIME, vol, interest, interest - dividend, isCall);
                 final double refPriceDiv = Math.max(Math.abs(priceDiv), 1.) / Math.sqrt(nSteps);
                 assertEquals(resDiv.get(Greek.FAIR_PRICE), priceDiv, refPriceDiv);
                 final double deltaDiv =
                     BlackScholesFormulaRepository.delta(
                         SPOT, strike, TIME, vol, interest, interest - dividend, isCall);
                 final double refDeltaDiv = Math.max(Math.abs(deltaDiv), 1.) / Math.sqrt(nSteps);
                 assertEquals(resDiv.get(Greek.DELTA), deltaDiv, refDeltaDiv);
                 final double gammaDiv =
                     BlackScholesFormulaRepository.gamma(
                         SPOT, strike, TIME, vol, interest, interest - dividend);
                 final double refGammaDiv = Math.max(Math.abs(gammaDiv), 1.) / Math.sqrt(nSteps);
                 assertEquals(resDiv.get(Greek.GAMMA), gammaDiv, refGammaDiv);
                 final double thetaDiv =
                     BlackScholesFormulaRepository.theta(
                         SPOT, strike, TIME, vol, interest, interest - dividend, isCall);
                 final double refThetaDiv = Math.max(Math.abs(thetaDiv), 1.) / Math.sqrt(nSteps);
                 assertEquals(resDiv.get(Greek.THETA), thetaDiv, refThetaDiv);
               }
             }
           }
         }
       }
     }
   }
 }
  @Test
  public void greekLeisenReimerTest() {
    final LatticeSpecification lattice = new LeisenReimerLatticeSpecification();

    final boolean[] tfSet = new boolean[] {true, false};
    for (final boolean isCall : tfSet) {
      for (final double strike : STRIKES) {
        for (final double interest : INTERESTS) {
          for (final double vol : VOLS) {
            final int[] choicesSteps = new int[] {31, 109, 301};
            for (final int nSteps : choicesSteps) {
              for (final double dividend : DIVIDENDS) {
                final OptionFunctionProvider1D function =
                    new EuropeanVanillaOptionFunctionProvider(strike, TIME, nSteps, isCall);
                final GreekResultCollection resDiv =
                    _model.getGreeks(lattice, function, SPOT, vol, interest, dividend);
                final double priceDiv =
                    BlackScholesFormulaRepository.price(
                        SPOT, strike, TIME, vol, interest, interest - dividend, isCall);
                final double refPriceDiv = Math.max(Math.abs(priceDiv), 1.) / nSteps;
                assertEquals(resDiv.get(Greek.FAIR_PRICE), priceDiv, refPriceDiv);
                final double deltaDiv =
                    BlackScholesFormulaRepository.delta(
                        SPOT, strike, TIME, vol, interest, interest - dividend, isCall);
                final double refDeltaDiv = Math.max(Math.abs(deltaDiv), 1.) / nSteps;
                assertEquals(resDiv.get(Greek.DELTA), deltaDiv, refDeltaDiv);
                final double gammaDiv =
                    BlackScholesFormulaRepository.gamma(
                        SPOT, strike, TIME, vol, interest, interest - dividend);
                final double refGammaDiv = Math.max(Math.abs(gammaDiv), 1.) / nSteps;
                assertEquals(resDiv.get(Greek.GAMMA), gammaDiv, refGammaDiv);
                final double thetaDiv =
                    BlackScholesFormulaRepository.theta(
                        SPOT, strike, TIME, vol, interest, interest - dividend, isCall);
                final double refThetaDiv = Math.max(Math.abs(thetaDiv), 1.) / nSteps;
                assertEquals(resDiv.get(Greek.THETA), thetaDiv, refThetaDiv * 10.);
              }
            }
          }
        }
      }
    }
  }
  /** The dividend is cash or proportional to asset price */
  @Test
  public void greeksDiscreteDividendLatticeTest() {
    final LatticeSpecification[] lattices =
        new LatticeSpecification[] {
          new CoxRossRubinsteinLatticeSpecification(),
          new JarrowRuddLatticeSpecification(),
          new TrigeorgisLatticeSpecification(),
          new JabbourKraminYoungLatticeSpecification(),
          new TianLatticeSpecification(),
          new LeisenReimerLatticeSpecification()
        };

    final double[] propDividends = new double[] {0.01, 0.01, 0.01};
    final double[] cashDividends = new double[] {5., 10., 8.};
    final double[] dividendTimes = new double[] {TIME / 420., TIME / 203., TIME / 2.};

    final boolean[] tfSet = new boolean[] {true, false};
    for (final LatticeSpecification lattice : lattices) {
      for (final boolean isCall : tfSet) {
        for (final double strike : STRIKES) {
          for (final double interest : INTERESTS) {
            for (final double vol : VOLS) {
              final int nSteps = 401;
              final double resSpot =
                  SPOT
                      * (1. - propDividends[0])
                      * (1. - propDividends[1])
                      * (1. - propDividends[2]);
              final double modSpot =
                  SPOT
                      - cashDividends[0] * Math.exp(-interest * dividendTimes[0])
                      - cashDividends[1] * Math.exp(-interest * dividendTimes[1])
                      - cashDividends[2] * Math.exp(-interest * dividendTimes[2]);
              final double exactPriceProp =
                  BlackScholesFormulaRepository.price(
                      resSpot, strike, TIME, vol, interest, interest, isCall);
              final double exactDeltaProp =
                  BlackScholesFormulaRepository.delta(
                      resSpot, strike, TIME, vol, interest, interest, isCall);
              final double exactGammaProp =
                  BlackScholesFormulaRepository.gamma(
                      resSpot, strike, TIME, vol, interest, interest);
              final double exactThetaProp =
                  BlackScholesFormulaRepository.theta(
                      resSpot, strike, TIME, vol, interest, interest, isCall);

              final double appPriceCash =
                  BlackScholesFormulaRepository.price(
                      modSpot, strike, TIME, vol, interest, interest, isCall);
              final double appDeltaCash =
                  BlackScholesFormulaRepository.delta(
                      modSpot, strike, TIME, vol, interest, interest, isCall);
              final double appGammaCash =
                  BlackScholesFormulaRepository.gamma(
                      modSpot, strike, TIME, vol, interest, interest);
              final double appThetaCash =
                  BlackScholesFormulaRepository.theta(
                      modSpot, strike, TIME, vol, interest, interest, isCall);

              final OptionFunctionProvider1D function =
                  new EuropeanVanillaOptionFunctionProvider(strike, TIME, nSteps, isCall);
              final DividendFunctionProvider cashDividend =
                  new CashDividendFunctionProvider(dividendTimes, cashDividends);
              final DividendFunctionProvider propDividend =
                  new ProportionalDividendFunctionProvider(dividendTimes, propDividends);
              final GreekResultCollection resProp =
                  _model.getGreeks(lattice, function, SPOT, vol, interest, propDividend);
              final GreekResultCollection resCash =
                  _model.getGreeks(lattice, function, SPOT, vol, interest, cashDividend);

              assertEquals(
                  resProp.get(Greek.FAIR_PRICE),
                  exactPriceProp,
                  Math.max(1., Math.abs(exactPriceProp)) * 1.e-2);
              assertEquals(
                  resProp.get(Greek.DELTA),
                  exactDeltaProp,
                  Math.max(1., Math.abs(exactDeltaProp)) * 1.e-1);
              assertEquals(
                  resProp.get(Greek.GAMMA),
                  exactGammaProp,
                  Math.max(1., Math.abs(exactGammaProp)) * 1.e-1);
              assertEquals(
                  resProp.get(Greek.THETA),
                  exactThetaProp,
                  Math.max(1., Math.abs(exactThetaProp)) * 1.e-1);

              assertEquals(
                  resCash.get(Greek.FAIR_PRICE),
                  appPriceCash,
                  Math.max(1., Math.abs(appPriceCash)) * 1.e-2);
              assertEquals(
                  resCash.get(Greek.DELTA),
                  appDeltaCash,
                  Math.max(1., Math.abs(appDeltaCash)) * 1.e-1);
              assertEquals(
                  resCash.get(Greek.GAMMA),
                  appGammaCash,
                  Math.max(1., Math.abs(appGammaCash)) * 1.e-1);
              assertEquals(
                  resCash.get(Greek.THETA), appThetaCash, Math.max(1., Math.abs(appThetaCash)));

              if (lattice instanceof CoxRossRubinsteinLatticeSpecification
                  || lattice instanceof JarrowRuddLatticeSpecification
                  || lattice instanceof TrigeorgisLatticeSpecification
                  || lattice instanceof TianLatticeSpecification) {
                final GreekResultCollection resPropTrinomial =
                    _modelTrinomial.getGreeks(lattice, function, SPOT, vol, interest, propDividend);
                final GreekResultCollection resCashTrinomial =
                    _modelTrinomial.getGreeks(lattice, function, SPOT, vol, interest, cashDividend);

                assertEquals(
                    resPropTrinomial.get(Greek.FAIR_PRICE),
                    resProp.get(Greek.FAIR_PRICE),
                    Math.max(1., Math.abs(resProp.get(Greek.FAIR_PRICE))) * 1.e-2);
                assertEquals(
                    resPropTrinomial.get(Greek.DELTA),
                    resProp.get(Greek.DELTA),
                    Math.max(1., Math.abs(resProp.get(Greek.DELTA))) * 1.e-2);

                assertEquals(
                    resPropTrinomial.get(Greek.GAMMA),
                    resProp.get(Greek.GAMMA),
                    Math.max(1., Math.abs(resProp.get(Greek.GAMMA))) * 1.e-2);
                assertEquals(
                    resPropTrinomial.get(Greek.THETA),
                    resProp.get(Greek.THETA),
                    Math.max(1., Math.abs(resProp.get(Greek.THETA))) * 1.e-1);

                assertEquals(
                    resCashTrinomial.get(Greek.FAIR_PRICE),
                    resCash.get(Greek.FAIR_PRICE),
                    Math.max(1., Math.abs(resCash.get(Greek.FAIR_PRICE))) * 1.e-2);
                assertEquals(
                    resCashTrinomial.get(Greek.DELTA),
                    resCash.get(Greek.DELTA),
                    Math.max(1., Math.abs(resCash.get(Greek.DELTA))) * 1.e-2);
                assertEquals(
                    resCashTrinomial.get(Greek.GAMMA),
                    resCash.get(Greek.GAMMA),
                    Math.max(1., Math.abs(resCash.get(Greek.GAMMA))) * 1.e-2);
                assertEquals(
                    resCashTrinomial.get(Greek.THETA),
                    resCash.get(Greek.THETA),
                    Math.max(1., Math.abs(resCash.get(Greek.THETA))) * 1.e-1);
              }
            }
          }
        }
      }
    }
  }