/**
   * Fit all the caps. Since there is some inconsistency in our data between ATM cap quotes and
   * those at absolute strikes (cap 'smiles' show the ATM quotes lying off a smooth curve through
   * the absolute strikes), we fit ATM quotes with an error of 1bps and everything else with an
   * error of 10bps. However, the resultant caplet volatility surface is less smooth (in the strike
   * direction) than that made excluding ATM.
   */
  @Test(description = "Demo of infering a caplet volatility surface")
  public void globalVolFitDemo() {
    final double lambdaT = 0.01; // this is chosen to give a chi2/DoF of around 1
    final double lambdaK = 0.0002;
    final List<CapFloor> allCaps = getAllCaps();
    System.out.println("number of caps :" + allCaps.size());
    final List<CapFloor> atmCaps = getATMCaps();
    final MultiCapFloorPricerGrid pricer = new MultiCapFloorPricerGrid(allCaps, getYieldCurves());
    final CapletStripperDirect stripper = new CapletStripperDirect(pricer, lambdaK, lambdaT);

    final double[] capVols = getAllCapVols();
    final int n = capVols.length;
    final double[] errors = new double[n];
    Arrays.fill(errors, 1e-3); // 10bps

    final int nATM = atmCaps.size();
    for (int i = 0; i < nATM; i++) {
      final int index = allCaps.indexOf(atmCaps.get(i));
      errors[index] = 1e-4; // 1bps
    }

    final DoubleMatrix1D guess = new DoubleMatrix1D(pricer.getGridSize(), 0.7);

    final CapletStrippingResult res = stripper.solve(capVols, MarketDataType.VOL, errors, guess);
    System.out.println("chi2 per cap: " + res.getChiSqr() / allCaps.size());
    System.out.println(res);

    res.printSurface(System.out, 101, 101);
    // res.printCapletVols(System.out);
  }
  /**
   * Fit the ATM caps only. Since there are only 7 such caps (in our data set), the resultant
   * 'surface' is close to a flat plane; this recovers the & cap vols and satisfies the curvature
   * penalties
   */
  @Test(description = "Demo of infering a caplet volatility surface")
  public void atmCapsOnlyDemo() {
    final double lambda = 0.7; // this is chosen to give a chi2/DoF of around 1
    final MultiCapFloorPricerGrid pricer =
        new MultiCapFloorPricerGrid(getATMCaps(), getYieldCurves());
    final CapletStripperDirect stripper = new CapletStripperDirect(pricer, lambda);

    final double[] capVols = getATMCapVols();
    final int n = capVols.length;
    final double[] errors = new double[n];
    Arrays.fill(errors, 1e-4); // 1bps
    final DoubleMatrix1D guess = new DoubleMatrix1D(pricer.getGridSize(), 0.7);

    final CapletStrippingResult res = stripper.solve(capVols, MarketDataType.VOL, errors, guess);
    System.out.println(res);

    System.out.println("Caplet volatility surface");
    res.printSurface(System.out, 101, 101);
  }