/// <summary>
 /// This method is unused but part of the interface.
 /// </summary>
 /// <param name="x">The parameter is not used.</param>
 /// <returns>Nothing the function always throws a NotImplementedException.</returns>
 public DVPLI.Vector Grad(DVPLI.Vector x)
 {
     throw new NotImplementedException();
 }
        /// <summary>
        /// Calibration objective function.
        /// </summary>
        /// <param name='x'>
        /// The vector of parameters.
        /// </param>
        /// <returns>
        /// Objective function value.
        /// </returns>
        public virtual double Obj(DVPLI.Vector x)
        {
            double sum = 0;
            if(Engine.MultiThread && !displayObjInfo)
            {
                // Instantiate parallel computation if enabled.
                List<Task> tl = new List<Task>();

                // Context contains both input parameters and outputs.
                List<HestonCall> context = new List<HestonCall>();
                for (int r = 0; r < this.callMarketPrice.R; r++)
                {
                    if (this.maturity[r] >= this.matBound[0])
                    {
                        HestonCall hc = new HestonCall(this, x, this.s0);
                        context.Add(hc);

                        hc.T = this.maturity[r];
                        hc.rate = this.rate[r];
                        if (HestonConstantDriftEstimator.impliedDividends)
                            hc.dividend = x[Range.End];
                        else
                            hc.dividend = this.dividendYield[r];
                        hc.row = r;
                        tl.Add(Task.Factory.StartNew(this.CalculateSingleRow, hc));
                    }
                }

                tsScheduler.WaitTaskList(tl);
                for (int r = 0; r < tl.Count; r++)
                        sum += context[r].sum;
            }
            else
            {
                // Sequential version of the code, used when parallel computation is disabled.
                HestonCall hc = new HestonCall(this, x, this.s0);
                for (int r = 0; r < this.callMarketPrice.R; r++)
                {
                    if (this.maturity[r] >= this.matBound[0])
                    {
                        hc.T = this.maturity[r];
                        hc.rate = this.rate[r];
                        if (HestonConstantDriftEstimator.impliedDividends)
                            hc.dividend = x[Range.End];
                        else
                            hc.dividend = this.dividendYield[r];
                        hc.row = r;
                        hc.sum = 0;
                        this.CalculateSingleRow(hc);
                        sum += hc.sum;
                    }
                }

                var pricingErrors = hc.hestonCallPrice - this.callMarketPrice;
                if (displayObjInfo)
                {
                    avgPricingError = 0;
                    for (int r = 0; r < this.callMarketPrice.R; r++)
                        if (this.maturity[r] >= this.matBound[0])
                        {
                            for (int c = 0; c < this.callMarketPrice.C; c++)
                            {
                                if (this.callMarketPrice[r, c] > s0 * optionThreshold && this.cpmd.CallVolume[r, c] > 0)
                                    avgPricingError += Math.Abs(pricingErrors[r, c]);
                                //if (this.cpmd.PutPrice[r, c] > s0 * optionThreshold && this.cpmd.PutVolume[r, c] > 0)
                                //    avgPricingError += Math.Abs(pricingErrors[r, c]);
                            }
                        }
                        avgPricingError /= numCall;

                    int RR = Math.Min(12, this.callMarketPrice.R - 1);
                    int CC = Math.Min(12, this.callMarketPrice.C - 1);
                    Console.WriteLine("Mkt Price");
                    Console.WriteLine(this.callMarketPrice[Range.New(0,RR),Range.New(0,CC)]);
                    Console.WriteLine("Pricing Errors");
                    Console.WriteLine(pricingErrors[Range.New(0, RR), Range.New(0, CC)]);
                }
                objCount++;
            }

            //Calculate average distance...
            sum = Math.Sqrt( sum /this.totalVolume);
            if (this.useBoundPenalty)
                sum += this.BoundPenalty(x);

            if (this.useFellerPenalty)
                sum +=this.FellerPenalty(x);

            return sum;
        }
        /// <summary>
        /// Calibration objective function:
        /// squared difference between black caps and Pelsser caps.
        /// </summary>
        /// <param name='x'>
        /// The tested [alpha, sigma] vector.
        /// </param>
        /// <returns>
        /// A scalar containing the sum of squared differences between
        /// black Caps and the Pelsser Caps.
        /// </returns>
        public double Obj(DVPLI.Vector x)
        {
            SquaredGaussianModel model = Assign(this.project, x);

            try
            {
                Matrix caps = this.caplet.PGSMCaplets(model, this.capMaturity, this.fwd, this.capK, this.deltaK, this.capMat);
                double sum = 0;
                for (int r = 0; r < caps.R; r++)
                {
                    for (int c = 0; c < caps.C; c++)
                    {
                        if (this.blackCaps[r, c] != 0.0)
                            sum += Math.Pow(caps[r, c] - this.blackCaps[r, c], 2);
                    }
                }

                double penalty=100*PelsserConstraint(this.project, x, 50).Norm();

                return Math.Sqrt(sum / (caps.R * caps.C)) + penalty;
            }
            catch (Exception)
            {
                return 1000 * x.Norm(NormType.L2);
            }
        }
 /// <summary>
 /// This method is unused but part of the interface.
 /// </summary>
 /// <param name="x">The parameter is not used.</param>
 /// <returns>Null as it's unused.</returns>
 public DVPLI.Vector G(DVPLI.Vector x)
 {
     return null;
 }
        /// <summary>
        /// Creates a representation of the Pelsser constraints.
        /// </summary>
        /// <remarks>
        /// The method is static in order to be used by other classes.
        /// </remarks>
        /// <param name="project">The project where to evaluate the constraints.</param>
        /// <param name="x">The vector of x values.</param>
        /// <param name="maturity">The cap maturity to use to evaluate the constraints.</param>
        /// <returns>
        /// A vector with the representation of the Pelsser constraints.
        /// </returns>
        public static DVPLI.Vector PelsserConstraint(ProjectROV project, DVPLI.Vector x, double maturity)
        {
            // This is modeled as a one-dimensional bound.
            SquaredGaussianModel model = Assign(project, x);
            Vector res = new Vector(1);

            double dt = 1.0 / (252);
            for (double t = 0; t <= maturity; t += dt)
                res[0] += Math.Max(0, -model.F2(t, dt)); // The square of F.

            /*
            dt = .1317;
            for (double t = 0; t <= 2; t += dt)
                res[0] +=Math.Max(0,-model.F2(t, dt)); // The square of F.

            dt = .25;
            for (double t = 0; t <= 2; t += dt)
                res[0] +=Math.Max(0,-model.F2(t, dt)); // The square of F.
            */

            return res;
        }
        /// <summary>
        /// Calibration objective function:
        /// squared difference between black swaptions and HW swaptions.
        /// </summary>
        /// <param name='x'>
        /// The tested [alpha, sigma] vector.
        /// </param>
        /// <returns>
        /// A double containing the squared difference between
        /// black swaptions and the HW swaptions.
        /// </returns>
        public double Obj(DVPLI.Vector x)
        {
            Matrix hwSWMatrix = this.shw1.HWSwaptionMatrix(this.swaptionMaturity, this.swapDuration, x[0], x[1], this.deltaK);
            double sum = 0;
            int count = this.swaptionMaturity.Length * this.swapDuration.Length;
            for (int r = 0; r < this.swaptionMaturity.Length; r++)
                for (int c = 0; c < this.swapDuration.Length; c++)
                    if (this.blackSwaption[r, c] != 0.0)
                        sum += Math.Pow(hwSWMatrix[r, c] - this.blackSwaption[r, c], 2);

            double bias = 0;
            double k = 25000;
            /*
            f.zr = this.shw1.zeroRateCurve;
            f.a = x[0];
            f.sigma = x[1];
            List<double> simDates, fR, avgR;
            f.Simulate(40, out simDates, out fR, out avgR);
            bias += Math.Abs(avgR[avgR.Count - 1] - f.zr.Evaluate(simDates[avgR.Count - 1]));
            Console.WriteLine(f.zr.Evaluate(simDates[avgR.Count - 1]) + "\t" + avgR[avgR.Count - 1] + "\t" + x[0] + "\t" + x[1] + "\t" + Math.Sqrt(sum / count));
            */

            return Math.Sqrt(sum / count )+k*bias;
        }
        public override double Obj(DVPLI.Vector x)
        {
            double kappa = x[0];
            double theta = x[1];
            double sigma = x[2];
            double rho = x[3];
            double v0 = x[4];

            if (displayObjInfo)
            {
                Console.WriteLine(".");
            }

            var paths = SimulateScenariosMT(s0, v0, kappa, theta, sigma, rho,Math.Min(this.matBound[1],this.cpmd.Maturity[Range.End]));

                if(displayObjInfo)
                {
                    Console.WriteLine("Average Underlying Scenario");
                    int Z=paths.Length;// number of time steps
                    int J = paths[0].Length;//number of realizations.
                    //display average path
                    for (int z = 0; z < Z; z++)
                    {
                        double avg = 0;
                        for (int j = 0; j < J; j++)
                            avg += paths[z][j];
                        avg /= J;

                        Console.WriteLine((z * dt) + "\t" + avg);
                    }

                }

                double sum = 0;
                int count = 0;

                for (int i = 0; i < this.cpmd.Maturity.Length; i++)
                {
                    double maturity = this.cpmd.Maturity[i];
                    if (maturity < matBound[0]|| maturity>matBound[1])
                        continue;

                    for (int j = 0; j < this.cpmd.Strike.Length; j++)
                    {
                        double strike = this.cpmd.Strike[j];
                        if (strike < strikeBound[0] * s0 || strike > strikeBound[1] * s0)
                            continue;

                        if(calibrateOnCallOptions)
                            if (this.cpmd.CallPrice[i, j] > s0 * optionThreshold)
                                if (cpmd.CallVolume[i, j] > 0)
                                {
                                    double call = CallPrice(paths, strike, maturity);
                                    sum += this.callWeight[i,j] * System.Math.Pow(this.cpmd.CallPrice[i, j] - call, 2.0);
                                    count++;
                                }

                        if(calibrateOnPutOptions)
                            if (cpmd.PutPrice != null)
                                if (cpmd.PutPrice[i, j] > s0 * optionThreshold)
                                    if (cpmd.PutVolume[i, j] > 0)
                                    {
                                        double put = PutPrice(paths, strike, maturity);

                                        sum += this.putWeight[i, j] * System.Math.Pow(cpmd.PutPrice[i, j] - put, 2.0);
                                        count++;
                                    }
                    }
                }
                double p = 0;

                //Frees memory
                for (int i = 0; i < paths.Length; i++)
                    paths[i].Dispose();

                if (this.useFellerPenalty)
                    p += this.FellerPenalty(x);

                if (double.IsNaN(sum) || double.IsInfinity(sum))
                    return p+10e5 * x.Norm();
                return p + Math.Sqrt(sum / this.totalVolume)/s0*100;
        }
        /// <summary>
        /// Calibration objective function:
        /// squared difference between black caps and hw caps.
        /// </summary>
        /// <param name='x'>
        /// The tested [alpha, sigma] vector.
        /// </param>
        /// <returns>
        /// A double containing the squared difference between
        /// black Caps and the HW Caps.
        /// </returns>
        public double Obj(DVPLI.Vector x)
        {
            Matrix hwCapsMatrix = this.hw1Caps.HWMatrixCaps(this.capMaturity, this.capRate, x[0], x[1], this.deltaK);
            double sum = 0;
            for (int r = 0; r < hwCapsMatrix.R; r++)
            {
                for (int c = 0; c < hwCapsMatrix.C; c++)
                {
                    if (this.blackCaps[r, c] != 0.0)
                        sum += Math.Pow(hwCapsMatrix[r, c] - this.blackCaps[r, c], 2);
                }
            }
            double bias = 0;
            /*
            f.zr = hw1Caps.zeroRateCurve;
            f.a = x[0];
            f.sigma = x[1];
            List<double> simDates, fR, avgR;
            f.Simulate(40, out simDates, out fR, out avgR);
            //double bias=f.ExpectedAverageRate(50) - hw1Caps.zeroRateCurve.Evaluate(50);

            for (int z = 0; z < simDates.Count; z++)
                bias += Math.Abs(avgR[z] - hw1Caps.zeroRateCurve.Evaluate(simDates[z]));
            Console.WriteLine(bias);
            */
            double k = 25000;
            return Math.Sqrt(sum ) + k * bias;
        }
        /// <summary>
        /// Calibration objective function:
        /// squared difference between black caps and Cox-Ingersoll-Ross caps.
        /// </summary>
        /// <param name='x'>
        /// The tested [kappa, theta, sigma] vector.
        /// </param>
        /// <returns>
        /// The distance (using the L2 norm) between
        /// black Caps and the Cox-Ingersoll-Ross Caps.
        /// </returns>
        public double Obj(DVPLI.Vector x)
        {
            Matrix cirCapMatrix = CIRCap.CIRCapMatrix(this.capMaturity, this.capRate,
                                                      this.tau, this.r0, x);
            double sum = 0;
            for (int r = 0; r < cirCapMatrix.R; r++)
            {
                for (int c = 0; c < cirCapMatrix.C; c++)
                {
                    if (this.blackCaps[r, c] != 0.0)
                        sum += Math.Pow(cirCapMatrix[r, c] - this.blackCaps[r, c], 2);
                }
            }

            return Math.Sqrt(sum);
        }