public InverseNonCentralChiSquareDistribution(double df, double ncp,
                                               int maxEvaluations,
                                               double accuracy)
 {
     nonCentralDist_ = new NonCentralChiSquareDistribution(df, ncp);
     guess_          = df + ncp;
     maxEvaluations_ = maxEvaluations;
     accuracy_       = accuracy;
 }
        public override double discountBondOption(Option.Type type,
                                                  double strike,
                                                  double maturity,
                                                  double bondMaturity)
        {
            Utils.QL_REQUIRE(strike > 0.0, () => "strike must be positive");
            double discountT = discountBond(0.0, maturity, x0());
            double discountS = discountBond(0.0, bondMaturity, x0());

            if (maturity < Const.QL_EPSILON)
            {
                switch (type)
                {
                case Option.Type.Call:
                    return(Math.Max(discountS - strike, 0.0));

                case Option.Type.Put:
                    return(Math.Max(strike - discountS, 0.0));

                default:
                    Utils.QL_FAIL("unsupported option type");
                    break;
                }
            }
            double sigma2 = sigma() * sigma();
            double h      = Math.Sqrt(k() * k() + 2.0 * sigma2);
            double b      = B(maturity, bondMaturity);

            double rho = 2.0 * h / (sigma2 * (Math.Exp(h * maturity) - 1.0));
            double psi = (k() + h) / sigma2;

            double df   = 4.0 * k() * theta() / sigma2;
            double ncps = 2.0 * rho * rho * x0() * Math.Exp(h * maturity) / (rho + psi + b);
            double ncpt = 2.0 * rho * rho * x0() * Math.Exp(h * maturity) / (rho + psi);

            NonCentralChiSquareDistribution chis = new NonCentralChiSquareDistribution(df, ncps);
            NonCentralChiSquareDistribution chit = new NonCentralChiSquareDistribution(df, ncpt);

            double z    = Math.Log(A(maturity, bondMaturity) / strike) / b;
            double call = discountS * chis.value(2.0 * z * (rho + psi + b)) -
                          strike * discountT * chit.value(2.0 * z * (rho + psi));

            if (type == Option.Type.Call)
            {
                return(call);
            }
            else
            {
                return(call - discountS + strike * discountT);
            }
        }