/** * Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.model.volatility.surface; import java.util.List; import com.opengamma.analytics.math.function.Function1D; import com.opengamma.analytics.math.function.Function2D; import com.opengamma.analytics.math.interpolation.BasisFunctionAggregation; import com.opengamma.analytics.math.interpolation.BasisFunctionGenerator; import com.opengamma.analytics.math.matrix.DoubleMatrix1D; import com.opengamma.analytics.math.surface.FunctionalDoublesSurface; import com.opengamma.analytics.math.surface.FunctionalSurface; import com.opengamma.analytics.math.surface.Surface; import com.opengamma.util.ArgumentChecker; import com.opengamma.util.tuple.Pair; /** * Represent a volatility surface using 2D basis-splines */ public class BasisSplineVolatilitySurfaceProvider implements VolatilitySurfaceProvider { private final List<Function1D<double[], Double>> _bSplines; public BasisSplineVolatilitySurfaceProvider(final List<Function1D<double[], Double>> bSlines) { ArgumentChecker.noNulls(bSlines, "null bSplines"); _bSplines = bSlines; } /** * Set up a volatility surface represented by weighted basis-splines * @param k1 The low strike value * @param k2 The upper strike value * @param nStrikeKnots Number of knots in strike direction * @param strikeDegree The degree of the basis-spline in the strike direction * @param t1 The low time * @param t2 The upper time * @param nTimeKnots Number of knots in time direction * @param timeDegree The degree of the basis-spline in the strike direction */ public BasisSplineVolatilitySurfaceProvider(final double k1, final double k2, final int nStrikeKnots, final int strikeDegree, final double t1, final double t2, final int nTimeKnots, final int timeDegree) { final BasisFunctionGenerator gen = new BasisFunctionGenerator(); _bSplines = gen.generateSet(new double[] {t1, k1 }, new double[] {t2, k2 }, new int[] {nTimeKnots, nStrikeKnots }, new int[] {timeDegree, strikeDegree }); } /** * {@inheritDoc} * The model parameters in this case are the weights of the basis-splines */ @Override public VolatilitySurface getVolSurface(final DoubleMatrix1D modelParameters) { ArgumentChecker.notNull(modelParameters, "modelParameters"); //BasisFunctionAggregation checks length of modelParameters final Function1D<double[], Double> func = new BasisFunctionAggregation<>(_bSplines, modelParameters.getData()); final Function2D<Double, Double> func2D = new Function2D<Double, Double>() { @Override public Double evaluate(final Double t, final Double k) { return func.evaluate(new double[] {t, k }); } }; final FunctionalDoublesSurface surface = new FunctionalDoublesSurface(func2D); return new VolatilitySurface(surface); } /** * {@inheritDoc} * The model parameters in this case are the weights of the basis-splines */ @Override public Surface<Double, Double, DoubleMatrix1D> getParameterSensitivitySurface(final DoubleMatrix1D modelParameters) { ArgumentChecker.notNull(modelParameters, "modelParameters"); //BasisFunctionAggregation checks length of modelParameters final BasisFunctionAggregation<double[]> bSpline = new BasisFunctionAggregation<>(_bSplines, modelParameters.getData()); final Function2D<Double, DoubleMatrix1D> func = new Function2D<Double, DoubleMatrix1D>() { @Override public DoubleMatrix1D evaluate(final Double t, final Double k) { return bSpline.weightSensitivity(new double[] {t, k }); } }; return new FunctionalSurface<>(func); } @Override public Surface<Double, Double, Pair<Double, DoubleMatrix1D>> getVolAndParameterSensitivitySurface(final DoubleMatrix1D modelParameters) { ArgumentChecker.notNull(modelParameters, "modelParameters"); //BasisFunctionAggregation checks length of modelParameters final BasisFunctionAggregation<double[]> bSpline = new BasisFunctionAggregation<>(_bSplines, modelParameters.getData()); final Function2D<Double, Pair<Double, DoubleMatrix1D>> func = new Function2D<Double, Pair<Double, DoubleMatrix1D>>() { @Override public Pair<Double, DoubleMatrix1D> evaluate(final Double t, final Double k) { return bSpline.valueAndWeightSensitivity(new double[] {t, k }); } }; return new FunctionalSurface<>(func); } /** * {@inheritDoc} * The number of parameters is the number of basis functions, which is #knots + degree - 1 in each dimension, so the * total is the product of this for strikes and times */ @Override public int getNumModelParameters() { return _bSplines.size(); } }