/**
   * Test interpolation part, essentially consistent with the super class (where extrapolation is
   * absent) iff local fitting is applied. If global fit is used, resulting interpolation is tested
   * with larger tolerance
   */
  @Test
  public void interpolationTest() {
    double eps = 1.0e-14;

    double expiry = 1.2;
    double forward = 1.7;
    int nStrikes = 11;
    double[] strikes = new double[nStrikes];
    double[] impliedVols =
        new double[] {
          2.17, 1.92, 1.702, 1.545, 1.281, 0.912, 0.9934, 1.0878, 1.1499, 1.2032, 1.242
        };
    for (int i = 0; i < nStrikes; ++i) {
      strikes[i] = forward * (0.85 + i * 0.05);
    }

    WeightingFunction weight = LinearWeightingFunction.getInstance();
    int seed = 4729;
    double beta = 0.95;

    ShiftedLogNormalExtrapolationFunctionProvider extapQuiet =
        new ShiftedLogNormalExtrapolationFunctionProvider("Quiet");
    SmileInterpolatorSABRWithExtrapolation interpQuiet =
        new SmileInterpolatorSABRWithExtrapolation(
            seed, new SABRHaganVolatilityFunction(), beta, weight, extapQuiet);
    InterpolatedSmileFunction funcQuiet =
        new InterpolatedSmileFunction(interpQuiet, forward, strikes, expiry, impliedVols);
    SmileInterpolatorSABR sabr =
        new SmileInterpolatorSABR(seed, new SABRHaganVolatilityFunction(), beta, weight);
    Function1D<Double, Double> volFunc =
        sabr.getVolatilityFunction(forward, strikes, expiry, impliedVols);

    int nKeys = 20;
    for (int i = 0; i < nKeys + 1; ++i) {
      Double key = strikes[0] + (strikes[nStrikes - 1] - strikes[0]) * i / nKeys;
      assertEquals(volFunc.evaluate(key), funcQuiet.getVolatility(key), eps);
    }

    SmileInterpolatorSABRWithExtrapolation interpGlobal1 =
        new SmileInterpolatorSABRWithExtrapolation(new SABRPaulotVolatilityFunction(), extapQuiet);
    SmileInterpolatorSABRWithExtrapolation interpGlobal2 =
        new SmileInterpolatorSABRWithExtrapolation(
            new SABRBerestyckiVolatilityFunction(), extapQuiet);
    SmileInterpolatorSABRWithExtrapolation interpGlobal3 =
        new SmileInterpolatorSABRWithExtrapolation(
            new SABRHaganAlternativeVolatilityFunction(), extapQuiet);
    InterpolatedSmileFunction funcGlobal1 =
        new InterpolatedSmileFunction(interpGlobal1, forward, strikes, expiry, impliedVols);
    InterpolatedSmileFunction funcGlobal2 =
        new InterpolatedSmileFunction(interpGlobal2, forward, strikes, expiry, impliedVols);
    InterpolatedSmileFunction funcGlobal3 =
        new InterpolatedSmileFunction(interpGlobal3, forward, strikes, expiry, impliedVols);
    for (int i = 0; i < nKeys + 1; ++i) {
      Double key = strikes[0] + (strikes[nStrikes - 1] - strikes[0]) * i / nKeys;
      double ref = funcQuiet.getVolatility(key);
      assertEquals(ref, funcGlobal1.getVolatility(key), 1.5 * ref * 1.0e-1);
      assertEquals(ref, funcGlobal2.getVolatility(key), ref * 1.0e-1);
      assertEquals(ref, funcGlobal3.getVolatility(key), ref * 1.0e-1);
    }
  }
  @Test
  public void hashCodeAndEqualsTest() {
    WeightingFunction weight = LinearWeightingFunction.getInstance();
    int seed = 4729;
    double beta = 0.95;
    ShiftedLogNormalExtrapolationFunctionProvider extapQuiet =
        new ShiftedLogNormalExtrapolationFunctionProvider("Quiet");
    ShiftedLogNormalExtrapolationFunctionProvider extapFlat =
        new ShiftedLogNormalExtrapolationFunctionProvider("Flat");
    SmileInterpolatorSABRWithExtrapolation interpQuiet1 =
        new SmileInterpolatorSABRWithExtrapolation(
            seed, new SABRHaganVolatilityFunction(), beta, weight, extapQuiet);
    SmileInterpolatorSABRWithExtrapolation interpQuiet2 =
        new SmileInterpolatorSABRWithExtrapolation(
            seed, new SABRHaganVolatilityFunction(), beta * 0.9, weight, extapQuiet);
    SmileInterpolatorSABRWithExtrapolation interpQuiet3 = interpQuiet1;
    SmileInterpolatorSABRWithExtrapolation interpQuiet4 =
        new SmileInterpolatorSABRWithExtrapolation(
            seed, new SABRHaganVolatilityFunction(), beta, weight, extapQuiet);
    SmileInterpolatorSABRWithExtrapolation interpFlat =
        new SmileInterpolatorSABRWithExtrapolation(
            seed, new SABRHaganVolatilityFunction(), beta, weight, extapFlat);

    assertTrue(interpQuiet1.equals(interpQuiet1));

    assertTrue(interpQuiet1.hashCode() == interpQuiet3.hashCode());
    assertTrue(interpQuiet1.equals(interpQuiet3));
    assertTrue(interpQuiet3.equals(interpQuiet1));

    assertFalse(interpQuiet1.equals(interpQuiet2));
    assertFalse(interpQuiet1.hashCode() == interpQuiet2.hashCode());

    assertFalse(interpQuiet1.equals(interpFlat));
    assertFalse(interpQuiet1.hashCode() == interpFlat.hashCode());

    assertTrue(interpQuiet1.hashCode() == interpQuiet4.hashCode());
    assertTrue(interpQuiet1.equals(interpQuiet4));
    assertTrue(interpQuiet4.equals(interpQuiet1));

    assertFalse(interpQuiet1.equals(null));
    assertFalse(interpQuiet1.equals(new SmileInterpolatorSABR()));
  }