/// <summary>
        /// Tests the price derivative with respect to forward for options in SABR model with extrapolation. Other data.
        /// </summary>
        public virtual void priceDerivativeSABR2()
        {
            double alpha  = 0.06;
            double beta   = 0.5;
            double rho    = 0.0;
            double nu     = 0.3;
            double cutOff = 0.10;
            double mu     = 2.5;
            double strike = 0.15;
            double t      = 2.366105247;
            EuropeanVanillaOption option   = EuropeanVanillaOption.of(strike, t, PutCall.CALL);
            SabrFormulaData       sabrData = SabrFormulaData.of(alpha, beta, rho, nu);
            double forward = 0.0404500579038675;
            SabrExtrapolationRightFunction sabrExtrapolation = SabrExtrapolationRightFunction.of(forward, t, sabrData, cutOff, mu);
            double          shift      = 0.000001;
            SabrFormulaData sabrDataAP = SabrFormulaData.of(alpha + shift, beta, rho, nu);
            SabrFormulaData sabrDataBP = SabrFormulaData.of(alpha, beta + shift, rho, nu);
            SabrFormulaData sabrDataRP = SabrFormulaData.of(alpha, beta, rho + shift, nu);
            SabrFormulaData sabrDataNP = SabrFormulaData.of(alpha, beta, rho, nu + shift);
            SabrExtrapolationRightFunction sabrExtrapolationAP = SabrExtrapolationRightFunction.of(forward, t, sabrDataAP, cutOff, mu);
            SabrExtrapolationRightFunction sabrExtrapolationBP = SabrExtrapolationRightFunction.of(forward, t, sabrDataBP, cutOff, mu);
            SabrExtrapolationRightFunction sabrExtrapolationRP = SabrExtrapolationRightFunction.of(forward, t, sabrDataRP, cutOff, mu);
            SabrExtrapolationRightFunction sabrExtrapolationNP = SabrExtrapolationRightFunction.of(forward, t, sabrDataNP, cutOff, mu);

            // Above cut-off strike
            double[]   abc   = sabrExtrapolation.Parameter;
            double[][] abcDP = sabrExtrapolation.ParameterDerivativeSabr;
//JAVA TO C# CONVERTER NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java:
//ORIGINAL LINE: double[][] abcPP = new double[4][3];
            double[][] abcPP = RectangularArrays.ReturnRectangularDoubleArray(4, 3);
            abcPP[0] = sabrExtrapolationAP.Parameter;
            abcPP[1] = sabrExtrapolationBP.Parameter;
            abcPP[2] = sabrExtrapolationRP.Parameter;
            abcPP[3] = sabrExtrapolationNP.Parameter;
//JAVA TO C# CONVERTER NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java:
//ORIGINAL LINE: double[][] abcDPExpected = new double[4][3];
            double[][] abcDPExpected = RectangularArrays.ReturnRectangularDoubleArray(4, 3);
            for (int loopparam = 0; loopparam < 4; loopparam++)
            {
                for (int loopabc = 0; loopabc < 3; loopabc++)
                {
                    abcDPExpected[loopparam][loopabc] = (abcPP[loopparam][loopabc] - abc[loopabc]) / shift;
                    assertEquals(1.0, abcDPExpected[loopparam][loopabc] / abcDP[loopparam][loopabc], 5.0E-2);
                }
            }
            double priceOutExpected = sabrExtrapolation.price(option.Strike, option.PutCall);

            double[] priceOutPP = new double[4];
            priceOutPP[0] = sabrExtrapolationAP.price(option.Strike, option.PutCall);
            priceOutPP[1] = sabrExtrapolationBP.price(option.Strike, option.PutCall);
            priceOutPP[2] = sabrExtrapolationRP.price(option.Strike, option.PutCall);
            priceOutPP[3] = sabrExtrapolationNP.price(option.Strike, option.PutCall);
            ValueDerivatives resOut   = sabrExtrapolation.priceAdjointSabr(option.Strike, option.PutCall);
            double           priceOut = resOut.Value;

            double[] priceOutDsabr = resOut.Derivatives.toArray();
            assertEquals(priceOutExpected, priceOut, 1E-5);
            double[] priceOutDsabrExpected = new double[4];
            for (int loopparam = 0; loopparam < 4; loopparam++)
            {
                priceOutDsabrExpected[loopparam] = (priceOutPP[loopparam] - priceOut) / shift;
                assertEquals(1.0, priceOutDsabrExpected[loopparam] / priceOutDsabr[loopparam], 4.0E-4);
            }
        }
        /// <summary>
        /// Tests the price derivative with respect to forward for options in SABR model with extrapolation.
        /// </summary>
        public virtual void priceDerivativeSabrPut()
        {
            SabrExtrapolationRightFunction func = SabrExtrapolationRightFunction.of(FORWARD, SABR_DATA, CUT_OFF_STRIKE, TIME_TO_EXPIRY, MU, SabrHaganVolatilityFunctionProvider.DEFAULT);
            double strikeIn  = 0.08;
            double strikeAt  = CUT_OFF_STRIKE;
            double strikeOut = 0.12;
            EuropeanVanillaOption optionIn  = EuropeanVanillaOption.of(strikeIn, TIME_TO_EXPIRY, PutCall.PUT);
            EuropeanVanillaOption optionAt  = EuropeanVanillaOption.of(strikeAt, TIME_TO_EXPIRY, PutCall.PUT);
            EuropeanVanillaOption optionOut = EuropeanVanillaOption.of(strikeOut, TIME_TO_EXPIRY, PutCall.PUT);
            double          shift           = 0.000001;
            SabrFormulaData sabrDataAP      = SabrFormulaData.of(ALPHA + shift, BETA, RHO, NU);
            SabrFormulaData sabrDataBP      = SabrFormulaData.of(ALPHA, BETA + shift, RHO, NU);
            SabrFormulaData sabrDataRP      = SabrFormulaData.of(ALPHA, BETA, RHO + shift, NU);
            SabrFormulaData sabrDataNP      = SabrFormulaData.of(ALPHA, BETA, RHO, NU + shift);
            SabrExtrapolationRightFunction sabrExtrapolationAP = SabrExtrapolationRightFunction.of(FORWARD, TIME_TO_EXPIRY, sabrDataAP, CUT_OFF_STRIKE, MU);
            SabrExtrapolationRightFunction sabrExtrapolationBP = SabrExtrapolationRightFunction.of(FORWARD, TIME_TO_EXPIRY, sabrDataBP, CUT_OFF_STRIKE, MU);
            SabrExtrapolationRightFunction sabrExtrapolationRP = SabrExtrapolationRightFunction.of(FORWARD, TIME_TO_EXPIRY, sabrDataRP, CUT_OFF_STRIKE, MU);
            SabrExtrapolationRightFunction sabrExtrapolationNP = SabrExtrapolationRightFunction.of(FORWARD, TIME_TO_EXPIRY, sabrDataNP, CUT_OFF_STRIKE, MU);
            // Below cut-off strike
            double priceInExpected = func.price(optionIn.Strike, optionIn.PutCall);

            double[] priceInPP = new double[4];
            priceInPP[0] = sabrExtrapolationAP.price(optionIn.Strike, optionIn.PutCall);
            priceInPP[1] = sabrExtrapolationBP.price(optionIn.Strike, optionIn.PutCall);
            priceInPP[2] = sabrExtrapolationRP.price(optionIn.Strike, optionIn.PutCall);
            priceInPP[3] = sabrExtrapolationNP.price(optionIn.Strike, optionIn.PutCall);
            ValueDerivatives resIn   = func.priceAdjointSabr(optionIn.Strike, optionIn.PutCall);
            double           priceIn = resIn.Value;

            double[] priceInDsabr = resIn.Derivatives.toArray();
            assertEquals(priceInExpected, priceIn, TOLERANCE_PRICE);
            double[] priceInDsabrExpected = new double[4];
            for (int loopparam = 0; loopparam < 3; loopparam++)
            {
                priceInDsabrExpected[loopparam] = (priceInPP[loopparam] - priceIn) / shift;
                assertEquals(priceInDsabrExpected[loopparam], priceInDsabr[loopparam], 1E-5);
            }
            // At cut-off strike
            double priceAtExpected = func.price(optionAt.Strike, optionAt.PutCall);

            double[] priceAtPP = new double[4];
            priceAtPP[0] = sabrExtrapolationAP.price(optionAt.Strike, optionAt.PutCall);
            priceAtPP[1] = sabrExtrapolationBP.price(optionAt.Strike, optionAt.PutCall);
            priceAtPP[2] = sabrExtrapolationRP.price(optionAt.Strike, optionAt.PutCall);
            priceAtPP[3] = sabrExtrapolationNP.price(optionAt.Strike, optionAt.PutCall);
            ValueDerivatives resAt   = func.priceAdjointSabr(optionAt.Strike, optionAt.PutCall);
            double           priceAt = resAt.Value;

            double[] priceAtDsabr = resAt.Derivatives.toArray();
            assertEquals(priceAtExpected, priceAt, TOLERANCE_PRICE);
            double[] priceAtDsabrExpected = new double[4];
            for (int loopparam = 0; loopparam < 3; loopparam++)
            {
                priceAtDsabrExpected[loopparam] = (priceAtPP[loopparam] - priceAt) / shift;
                assertEquals(priceAtDsabrExpected[loopparam], priceAtDsabr[loopparam], 1E-5);
            }
            // Above cut-off strike
            double priceOutExpected = func.price(optionOut.Strike, optionOut.PutCall);

            double[] priceOutPP = new double[4];
            priceOutPP[0] = sabrExtrapolationAP.price(optionOut.Strike, optionOut.PutCall);
            priceOutPP[1] = sabrExtrapolationBP.price(optionOut.Strike, optionOut.PutCall);
            priceOutPP[2] = sabrExtrapolationRP.price(optionOut.Strike, optionOut.PutCall);
            priceOutPP[3] = sabrExtrapolationNP.price(optionOut.Strike, optionOut.PutCall);
            ValueDerivatives resOut   = func.priceAdjointSabr(optionOut.Strike, optionOut.PutCall);
            double           priceOut = resOut.Value;

            double[] priceOutDsabr = resOut.Derivatives.toArray();
            assertEquals(priceOutExpected, priceOut, TOLERANCE_PRICE);
            double[]   abc   = func.Parameter;
            double[][] abcDP = func.ParameterDerivativeSabr;
//JAVA TO C# CONVERTER NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java:
//ORIGINAL LINE: double[][] abcPP = new double[4][3];
            double[][] abcPP = RectangularArrays.ReturnRectangularDoubleArray(4, 3);
            abcPP[0] = sabrExtrapolationAP.Parameter;
            abcPP[1] = sabrExtrapolationBP.Parameter;
            abcPP[2] = sabrExtrapolationRP.Parameter;
            abcPP[3] = sabrExtrapolationNP.Parameter;
//JAVA TO C# CONVERTER NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java:
//ORIGINAL LINE: double[][] abcDPExpected = new double[4][3];
            double[][] abcDPExpected = RectangularArrays.ReturnRectangularDoubleArray(4, 3);
            for (int loopparam = 0; loopparam < 4; loopparam++)
            {
                for (int loopabc = 0; loopabc < 3; loopabc++)
                {
                    abcDPExpected[loopparam][loopabc] = (abcPP[loopparam][loopabc] - abc[loopabc]) / shift;
                    assertEquals(1.0, abcDPExpected[loopparam][loopabc] / abcDP[loopparam][loopabc], 5.0E-2);
                }
            }
            double[] priceOutDsabrExpected = new double[4];
            for (int loopparam = 0; loopparam < 4; loopparam++)
            {
                priceOutDsabrExpected[loopparam] = (priceOutPP[loopparam] - priceOut) / shift;
                assertEquals(1.0, priceOutDsabrExpected[loopparam] / priceOutDsabr[loopparam], 4.0E-4);
            }
        }