@Test
  public void sensitivityTest() {
    final VolatilitySurfaceProvider vsPro =
        new BasisSplineVolatilitySurfaceProvider(0.0, 0.15, 10, 3, 0.0, 10.0, 7, 2);

    final DoubleMatrix1D w = new DoubleMatrix1D(vsPro.getNumModelParameters());
    for (int i = 0; i < w.getNumberOfElements(); i++) {
      w.getData()[i] = RANDOM.nextDouble();
    }

    final VolatilitySurface volSurf = vsPro.getVolSurface(w);
    final Surface<Double, Double, DoubleMatrix1D> senseSurf =
        vsPro.getParameterSensitivitySurface(w);
    final Surface<Double, Double, Pair<Double, DoubleMatrix1D>> volAndSenseSurf =
        vsPro.getVolAndParameterSensitivitySurface(w);

    final int nSamples = 20;
    final DoublesPair[] points = new DoublesPair[nSamples];
    for (int i = 0; i < nSamples; i++) {
      final double t = 10.0 * RANDOM.nextDouble();
      final double k = 0.15 * RANDOM.nextDouble();
      points[i] = DoublesPair.of(t, k);

      final double vol = volSurf.getVolatility(points[i]);
      final DoubleMatrix1D sense = senseSurf.getZValue(points[i].toPair());
      final Pair<Double, DoubleMatrix1D> volAndSense =
          volAndSenseSurf.getZValue(points[i].toPair());
      assertEquals(vol, volAndSense.getFirst(), 1e-15);
      AssertMatrix.assertEqualsVectors(sense, volAndSense.getSecond(), 1e-15);
    }

    // create a DiscreteVolatilityFunctionProvider in order to compute the Jacobian for a (random)
    // set the points
    final DiscreteVolatilityFunctionProvider dvfp =
        new DiscreteVolatilityFunctionProviderFromVolSurface(vsPro);
    final DiscreteVolatilityFunction func = dvfp.from(points);
    final DoubleMatrix2D jac = func.calculateJacobian(w);
    final DoubleMatrix2D jacFD = func.calculateJacobianViaFD(w);
    AssertMatrix.assertEqualsMatrix(jacFD, jac, 1e-10);
  }
  @Test
  public void test() {
    final int nSamples = 10;
    final List<DoublesPair> points = new ArrayList<>(nSamples);
    final DoubleMatrix1D x = new DoubleMatrix1D(nSamples);
    for (int i = 0; i < nSamples; i++) {
      final double t = RANDOM.nextDouble() * 20.0;
      final double k = RANDOM.nextDouble() * 0.15;
      points.add(DoublesPair.of(t, k));
      x.getData()[i] = RANDOM.nextDouble();
    }

    final DiscreteVolatilityFunctionProvider pro = new DiscreteVolatilityFunctionProviderDirect();
    final DiscreteVolatilityFunction func = pro.from(points);
    final DoubleMatrix1D y = func.evaluate(x);
    AssertMatrix.assertEqualsVectors(x, y, 0.0);
    final DoubleMatrix2D jac = func.calculateJacobian(x);
    AssertMatrix.assertEqualsMatrix(new IdentityMatrix(nSamples), jac, 0.0);

    assertEquals(nSamples, func.getLengthOfDomain());
    assertEquals(nSamples, func.getLengthOfRange());
  }