// Golden Section search form Heston
        public double GoldenSearchMS(double a, double b, double tol, int MaxIter, double K, HParam param, double theta, double r, double q, double T, int NumTerms)
        {
            MSExpansionHeston MS = new MSExpansionHeston();
            double            x1, x2, x3, x4, f1, f2, f3, f4;
            double            GR = (Math.Sqrt(5.0) - 1.0) / 2.0;
            int k = 0;

            while (Math.Abs(b - a) > tol)
            {
                k  = k + 1;
                x1 = a;
                x2 = a + (1.0 - GR) * (b - a);
                x3 = a + GR * (b - a);
                x4 = b;
                f1 = -MS.MSPutHeston(x1, theta, K, param, r, q, T, NumTerms);
                f2 = -MS.MSPutHeston(x2, theta, K, param, r, q, T, NumTerms);
                f3 = -MS.MSPutHeston(x3, theta, K, param, r, q, T, NumTerms);
                f4 = -MS.MSPutHeston(x4, theta, K, param, r, q, T, NumTerms);
                if ((f1 > f2) & (f2 < f3))
                {
                    b = x3;
                }
                else if ((f2 > f3) & (f3 < f4))
                {
                    a = x2;
                }
                if (k > MaxIter)
                {
                    break;
                }
            }
            return((a + b) / 2.0);
        }
        public double[] MSPriceHeston(HParam param, OpSet opset, MSSet msset)
        {
            // param  = Heston parameters
            // opset  = option settings
            // msset  = Medvedev-Scaillet expansion settings

            // Extract quantities from the option settings
            double K  = opset.K;
            double S  = opset.S;
            double v0 = param.v0;
            double T  = opset.T;
            double r  = opset.r;
            double q  = opset.q;

            // Extract quantities from the MS structure
            int    N        = msset.N;
            double a        = msset.a;
            double b        = msset.b;
            double A        = msset.A;
            double B        = msset.B;
            double dt       = msset.dt;
            double tol      = msset.tol;
            int    MaxIter  = msset.MaxIter;
            int    NumTerms = msset.NumTerms;
            double yinf     = msset.yinf;
            int    method   = msset.method;

            // Closed-form European put
            NewtonCotes NC            = new NewtonCotes();
            double      EuroPutClosed = NC.HestonPriceNewtonCotes(param, opset, method, A, B, N);

            // Moneyness
            double theta = Math.Log(K / S) / Math.Sqrt(v0) / Math.Sqrt(T);

            // Find the barrier level
            // Bisection method to find y
            // a = Math.Max(1.25,0.95*theta);
            // b = 3.0;
            // double y = BisectionMS(a,b,theta,K,param,r,q,T,NumTerms,tol,MaxIter,dt);

            // Golden section search method to find y
            GoldenSearch GS = new GoldenSearch();

            a = 1.5;
            b = 2.5;
            double y = GS.GoldenSearchMS(a, b, tol, MaxIter, K, param, theta, r, q, T, NumTerms);

            if (y < theta)
            {
                y = theta;
            }

            // Find the early exercise premium
            MSExpansionHeston MS        = new MSExpansionHeston();
            double            AmerPutMS = MS.MSPutHeston(y, theta, K, param, r, q, T, NumTerms);
            double            EuroPutMS = MS.MSPutHeston(yinf, theta, K, param, r, q, T, NumTerms);
            double            EEP       = AmerPutMS - EuroPutMS;

            // Control variate American put
            double AmerPut = EuroPutClosed + EEP;

            // Output the results
            double[] output = new double[6];
            output[0] = EuroPutClosed;
            output[1] = AmerPutMS;
            output[2] = AmerPut;      // Medvedev and Scaillet recommend this one.
            output[3] = EEP;
            output[4] = theta;
            output[5] = y;
            return(output);
        }
        // Derivative of the MS approximation
        public double MSPutHestonDiff(double y, double theta, double Strike, HParam param, double r, double q, double T, int NumTerms, double dy)
        {
            MSExpansionHeston MS = new MSExpansionHeston();

            return((MS.MSPutHeston(y + dy, theta, Strike, param, r, q, T, NumTerms) - MS.MSPutHeston(y - dy, theta, Strike, param, r, q, T, NumTerms)) / 2.0 / dy);
        }