// Heston Price by Gauss-Legendre Integration
        public OutputMD HestonPriceGaussLegendreMD(HParam param, OpSet settings, double[] xGLe, double[] wGLe, double[] A, double tol)
        {
            int nA = A.Length;
            int nX = xGLe.Length;

            double[,] int1 = new double[nA, nX];
            double[,] int2 = new double[nA, nX];
            double[] sum1 = new double[nA];
            double[] sum2 = new double[nA];

            // Numerical integration
            HestonPrice HP = new HestonPrice();
            int         nj = 0;

            for (int j = 1; j <= nA - 1; j++)
            {
                // Counter for the last point of A used
                nj     += 1;
                sum1[j] = 0.0;
                for (int k = 0; k <= nX - 1; k++)
                {
                    // Lower and upper and limits of the subdomain
                    double a = A[j - 1];
                    double b = A[j];
                    double X = (a + b) / 2.0 + (b - a) / 2.0 * xGLe[k];
                    int1[j, k] = wGLe[k] * HP.HestonProb(X, param, settings, 1) * (b - a) / 2.0;
                    int2[j, k] = wGLe[k] * HP.HestonProb(X, param, settings, 2) * (b - a) / 2.0;
                    sum1[j]   += int1[j, k];
                    sum2[j]   += int2[j, k];
                }
                if (Math.Abs(sum1[j]) < tol && Math.Abs(sum2[j]) < tol)
                {
                    break;
                }
            }

            // Define P1 and P2
            double pi = Math.PI;
            double P1 = 0.5 + 1.0 / pi * sum1.Sum();
            double P2 = 0.5 + 1.0 / pi * sum2.Sum();

            // The call price
            double S       = settings.S;
            double K       = settings.K;
            double T       = settings.T;
            double r       = settings.r;
            double q       = settings.q;
            string PutCall = settings.PutCall;
            double HestonC = S * Math.Exp(-q * T) * P1 - K * Math.Exp(-r * T) * P2;

            // The put price by put-call parity
            double HestonP = HestonC - S * Math.Exp(-q * T) + K * Math.Exp(-r * T);

            // The output structure
            OutputMD output = new OutputMD();

            // Output the option price
            if (PutCall == "C")
            {
                output.Price = HestonC;
            }
            else
            {
                output.Price = HestonP;
            }

            // Output the integration domain;
            output.lower = A[0];
            output.upper = A[nj];

            // Output the number of integration points
            output.Npoints = (nj + 1) * nX;
            return(output);
        }
        static void Main(string[] args)
        {
            // 32-point Gauss-Legendre Abscissas and weights
            double[] xGLe = new Double[32];
            double[] wGLe = new Double[32];
            using (TextReader reader = File.OpenText("../../GaussLegendre32.txt"))
            {
                for (int k = 0; k <= 31; k++)
                {
                    string   text = reader.ReadLine();
                    string[] bits = text.Split(' ');
                    xGLe[k] = double.Parse(bits[0]);
                    wGLe[k] = double.Parse(bits[1]);
                }
            }

            // Heston parameters
            HParam param = new HParam();

            param.kappa  = 2.0;
            param.theta  = 0.05;
            param.sigma  = 0.3;
            param.v0     = 0.05;
            param.rho    = 0.45;
            param.lambda = 0.0;

            // Option price settings
            OpSet settings = new OpSet();

            settings.S       = 100.0;
            settings.K       = 100.0;
            settings.r       = 0.05;
            settings.q       = 0.01;
            settings.trap    = 1;
            settings.PutCall = "C";
            settings.T       = 0.5;

            // Price by Simpson's rule
            NewtonCotesPrice NCP = new NewtonCotesPrice();
            int    method        = 3;
            double a             = 1e-10;
            double b             = 150;
            int    NS            = 10000;
            double PriceSimpson  = NCP.HestonPriceNewtonCotes(param, settings, method, a, b, NS);

            // Potential integration domain
            double lo = 1e-10;
            double hi = 150;
            int    N  = 1000;
            double dA = (hi - lo) / Convert.ToDouble(N);

            double[] A = new double[N];
            for (int j = 0; j <= N - 1; j++)
            {
                A[j] = lo + j * dA;
            }

            // The modified domain Gauss-Legendre price
            HestonPriceMD HPMD    = new HestonPriceMD();
            double        tol     = 1e-6;
            OutputMD      output  = HPMD.HestonPriceGaussLegendreMD(param, settings, xGLe, wGLe, A, tol);
            double        PriceMD = output.Price;
            double        lower   = output.lower;
            double        upper   = output.upper;
            int           Npoints = output.Npoints;
            double        errorMD = PriceMD - PriceSimpson;

            // The price using Newton Cotes
            double PriceNC = NCP.HestonPriceNewtonCotes(param, settings, method, lower, upper, Npoints);
            double errorNC = PriceNC - PriceSimpson;

            // Write the results
            Console.WriteLine("Zhu Multi-Domain Integration Algorithm");
            Console.WriteLine("-------------------------------------------");
            Console.WriteLine("Multi-Domain tolerance      {0:E3}", tol);
            Console.WriteLine("Lower integration limit     {0:E3}", lower);
            Console.WriteLine("Upper integration limit     {0:F3}", upper);
            Console.WriteLine("Number of integration pts   {0:0}", Npoints);
            Console.WriteLine("-------------------------------------------");
            Console.WriteLine("Method                 Price        Error ");
            Console.WriteLine("-------------------------------------------");
            Console.WriteLine("{0:0}-point Simpson  {1,10:F4}", N, PriceSimpson);
            Console.WriteLine("Multi-Domain        {0,10:F4} {1,10:F4}", PriceMD, errorMD);
            Console.WriteLine("Newton-Cotes        {0,10:F4} {1,10:F4}", PriceNC, errorNC);
            Console.WriteLine("-------------------------------------------");
        }